package gbench.sandbox.matrix.img.util;

import java.awt.image.BufferedImage;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Stack;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import gbench.common.fs.XlsFile.DataMatrix;

import static java.lang.Math.PI;
import static java.lang.Math.cos;
import static java.lang.Math.sin;

/**
 * 数学家画布 <br>
 * 一个绘图画布就是 通过提供一条轴向采样点，然后不断进行维度扩增而建构span出一种 图形图像(形状) 的 空间的思维&工具框架。<br>
 * MatlibCanvas 的本质(思想) 是 空间构建器. <br>
 * <br>
 * MatlibCanvas 的关键是它对 绘图的基本概念的设计。<br>
 * MatlibCanvas 的本质就是对 空间的操作。<br>
 * MatlibCanvas 把空间视为维度范围(Range)的结构。每个维度范围是由 (start,end,step) 三元组构成。<br>
 * Range 维度范围 提供出一组方便的 采样点结构 的生成方法(map,dblA,dblS等) 以及 维度范围组织方法(span)。<br>
 * 这样我们构造除了一种 多维空间的 立体采样点 框架。<br>
 * 在这个立体的 采样框架中(采样点空间)，我们可以借助于RangeMap除垢的含有采样点坐标索引信息的数据，即空间结构概念点Point.
 * 一个每个Point，就被视为 一种 索引键值结构:IdxValPair 即IVP,
 * 可以通过对  Index 的变换(IdxValPair.analze) 将数据分理处 坐标索引即空间嘻嘻 以及 索引值即 空间点内容。于是对空间的
 * 操作就变成了对 IVP的操作。为了方便计算我们把IVP做了特化，即索引结构采用int[],即整数列表的方式。
 * 以方便与cartesian坐标系对应。于是对空间的操作就变成对IVP的操作。
 * 我们采用向量化思想来管理，操作IndexValue结构。为此我们专门设计TVec这种类型化的数组操作结构，并针对于绘图<br>
 * 要求的制作了NVec来作为MatlibCanvas的主要 点数据的操作工具。这样在NVec的协助呀我们就可以 对各种数学概念进行绘图<br>
 * 对于平面图像图像。我们采用一个5维向量xyrgb[x,y,r,g,b]来表示，所以一副图片就对应于一个xyrgb的向量列表。于是<br>
 * 对图片的创建修改与操作就变成了对xyrgb列表的操作。xyrgb有可以被轻易的转换成矩阵结构。于是我们就可以采用矩阵的的方式<br>
 * 来操作xyrgb列表。[xyrgb]。这也是为何我们把绘图操作叫做MatlibCanvas的即，每个个绘图操作都是可以视为一种矩阵计算。<br>
 *  
 * @author gbench
 */
public class MatlibCanvas {
    
    /**
     * 数学家画布  <br>
     * param start 开始位置 默认为 0 inclusive <br>
     * param end 结束位置  默认为 500 exclusive
     */
    public MatlibCanvas(){
        
        this(0,500,1);
    }
    
    /**
     * 数学家画布  <br>
     * param start 开始位置 默认为 0 inclusive <br>
     * @param end 结束位置 exclusive 
     */
    public MatlibCanvas(final Number end){
        
        this(0,end,1);
    }
    
    /**
     * @param start 开始位置 inclusive 
     * @param end 结束位置 exclusive
     */
    public MatlibCanvas(final Number start,final Number end){
        
        this(start,end,1);
    }
    
    /**
     * 数学家画布
     * @param start 开始位置 inclusive
     * @param end 结束位置 exclusive
     */
    public MatlibCanvas(final Number start,final Number end,final Number step){
        
        this.range = new Range(start,end,step);
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Function<Double,Double> fx){
        
        return this.drawLine(fx,(Boolean)null);
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Function<Double,Double> fx,final Boolean flipFlag){
        
        return this.drawLine(fx, (int[])null,(Boolean)flipFlag);
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param color 线条颜色
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Function<Double,Double> fx, final int[] color){
        
        return this.drawLine(fx,color,(Boolean)null);
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param color 线条颜色
     * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Function<Double,Double> fx, final int[] color, final Boolean flipFlag){
        
        return this.drawLine(null,fx,color,flipFlag);
    }
    
    /**
     * 绘制一条曲线
     * @param range x的变化范围
     * @param fx y值函数
     * @param color 颜色现象
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Range range, final Function<Double,Double> fx, final int[] color){
        
        return this.drawLine(range,fx,color,(Boolean)null);
    }
    
    /**
     * 绘制一条曲线
     * @param range x的变化范围
     * @param fx y值函数
     * @param color 颜色现象
     * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Range range, final Function<Double,Double> fx, 
        final int[] color, final Boolean flipFlag){
        
        final var clr = (color==null ? this.color : color); // 线条颜色
        final var stream = this.drawLine( range, fx,  (x,y)-> point(x,y,clr,flipFlag) );
        
        return stream.flatMap( continuous_line() );
    }
    
    /**
     * 绘制一条曲线
     * @param start 开始顶点
     * @param end 结束点 exclusive
     * @param fx y值函数
     * @param color 线条颜色
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public Stream<int[]> drawLine(final Number start,final Number end,
        final Function<Double,Double> fx, final int[] color){
        
        return this.drawLine(new Range(start,end), fx, color);
    }

    /**
     * 绘制一条曲线
     * @param <T> 节点序列的元素类型
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> Stream<T> drawLine(final Function<Double,Double> fx,final BiFunction<Double,Double,T> point_renderer){
        
        return this.drawLine(null,fx, point_renderer);
    }
    
    /**
     * 绘制一条曲线
     * <核心函数>
     * @param <T> 节点序列的元素类型
     * @param range x 的变化范围
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> Stream<T> drawLine(final Range range, final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer){
        
        final var rng = (range == null ? this.range : range);
        
        return rng.dblStream().map(x -> point_renderer.apply(x, fx.apply(x)));
    }

    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public List<int[]> drawLine2(final Function<Double,Double> fx){
        
        return this.drawLine(fx).collect(Collectors.toList());
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param color 线条颜色
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public List<int[]> drawLine2(final Function<Double,Double> fx,int[] color){
        
        return this.drawLine(fx,color).collect(Collectors.toList());
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param color 线条颜色
     * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public List<int[]> drawLine2(final Function<Double,Double> fx,int[] color,Boolean flipFlag){
        
        return this.drawLine2(range,fx,color,flipFlag);
    }
    
    /**
     * 绘制一条曲线
     * @param fx y值函数
     * @param color 线条颜色
     * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
     * @return 节点序列:[[x,y,r,g,b]]
     */
    public List<int[]> drawLine2(final Range range,final Function<Double,Double> fx,
        int[] color,Boolean flipFlag){
        
        return this.drawLine(range,fx,color,flipFlag).collect(Collectors.toList());
    }
    
    /**
     * 绘制一条曲线
     * @param <T> 节点序列的元素类型
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> List<T> drawLine2(final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer){
        
        return this.drawLine2((Range)null,fx, point_renderer);
    }

    /**
     * 绘制一条曲线
     * @param <T> 节点序列的元素类型
     * @param range x 的变化范围
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> List<T> drawLine2(final Range range,final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer){
        
        return this.drawLine(range,fx, point_renderer).collect(Collectors.toList());
    }
    
    /**
     * 绘制一条曲线
     * 核心函数 <br>
     * @param <T> 节点序列的元素类型
     * @param range x 的变化范围
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @param indexer 行号 列号 t->{行索引,列索引}
     * @param valueer 值提取 t->u 
     * @return 节点序列:[t]
     */
    public <T,U> U[][] drawLine3(final Range range,final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer,
        final Function<T,int[]> indexer,final Function<T,U> valueer){
        
        return matrix(this.drawLine(range,fx, point_renderer).collect(Collectors.toList()),indexer,valueer);
    }
    
    /**
     * 绘制一条曲线
     * 核心函数 <br>
     * @param <T> 节点序列的元素类型
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @param indexer 行号 列号 t->{行索引,列索引}
     * @param valueer 值提取 t->u 
     * @return 节点序列:[t]
     */
    public <T,U> U[][] drawLine3(final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer,
        final Function<T,int[]> indexer,final Function<T,U>valueer){
        
        return matrix(this.drawLine(fx, point_renderer).collect(Collectors.toList()),
            indexer,valueer);
    }
    
    /**
     * 绘制一条曲线
     * 核心函数 <br>
     * @param <T> 节点序列的元素类型
     * @param fx y值函数
     * @param valueer 值提取 t->u 
     * @return 节点矩阵 行号是x,列号是y
     */
    public <T> int[][][] drawLine3(final Function<Double,Double> fx){
        
        return matrix(this.drawLine(fx).collect(Collectors.toList()),e->e
            ,e->Arrays.copyOfRange(e, 2, e.length));
    }
    
    /**
     * 点向量
     * 
     * @param x 水平坐标
     * @param y 垂直坐标
     * @return [x,y,r,g,b]
     */
    public int[] point(final Number x,final Number y) {
        
       return point(x,y,null,false);
    }

    /**
     * 点向量
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param rgb 色彩数组
     * @return [x,y,r,g,b]
     */
    public int[] point(final Number x,final Number y,final int[]rgb) {
        
        return point(x,y,rgb,null);
    }
    
    /**
     * 点向量
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param rgb 色彩数组
     * @param flipFlag 是否调转 索引坐标  x,y位置
     * @return [x,y,r,g,b]
     */
    public int[] point(final Number x,final Number y,final int[]rgb,final Boolean flipFlag) {
        
        final var clr = (rgb==null?this.color:rgb);//色彩向量
        final var p = ( flipFlag==null ? this.flipFlag : flipFlag )
            ? new int[] {y.intValue(),x.intValue(), clr[0],clr[1],clr[2]}
            : new int[] {x.intValue(),y.intValue(), clr[0],clr[1],clr[2]};
            
        return p;
    }
    
    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param point [x水平坐标,y垂直坐标]
     * @return NVec 对象
     */
    public NVec xY(final NVec point){
        
        if(point==null||point.size()<2)return null;
        
        return this.xY(point.get(0),point.get(1));
    }

    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平坐标
     * @param y 垂直坐标
     * @return NVec 对象
     */
    public NVec xY(final Number x,final Number y) {
        
        return cartesian_point_nvec(x,y);
    }
    
    /**
     * 笛卡尔坐标 形式的 点结构
     * 
     * @param x 水平坐标
     * @param y 垂直坐标
     * @return NVec 对象
     */
    public NVec cartesian_point_nvec(final Number x,final Number y) {
        
       return this.cartesian_point_nvec(x, y, (int[])null, flipFlag);
    }
    
    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平坐标
     * @param y 垂直坐标
     * @param flipFlag 是否调转 索引坐标  x,y位置
     * @return NVec 对象
     */
    public NVec xY(final Number x,final Number y,final Boolean flipFlag) {
        
        return cartesian_point_nvec(x,y,flipFlag);
    }

    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平坐标
     * @param y 垂直坐标
     * @param flipFlag 是否调转 索引坐标  x,y位置
     * @return NVec 对象
     */
    public NVec cartesian_point_nvec(final Number x,final Number y,
        final Boolean flipFlag) {
        
        return this.cartesian_point_nvec(x, y, (int[])null, flipFlag);
    }
    
    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param rgb 色彩数组
     * @return NVec 对象
     */
    public NVec xY(final Number x, final Number y,final int[]rgb) {
        
        return this.cartesian_point_nvec(x, y, rgb);
    }

    /**
     * 笛卡尔坐标 形式的 点结构
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param rgb 色彩数组
     * @return NVec 对象
     */
    public NVec cartesian_point_nvec(final Number x, final Number y,final int[]rgb) {
        
        return this.cartesian_point_nvec(x, y, rgb, null);
    }

    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param rgb 色彩数组
     * @param flipFlag 是否调转 索引坐标  x,y位置
     * @return NVec 对象
     */
    public NVec xY(final Number x, final Number y,
        final int[]rgb, final Boolean flipFlag) {
        
        return this.cartesian_point_nvec(x, y, rgb, flipFlag);
    }
    
    /**
     * 笛卡尔坐标 形式的 点结构  <br>
     * cartesian_point_nvec的别名 <br>
     * 
     * @param x 水平偏移 
     * @param y 垂直偏移
     * @param r 红色分量
     * @param g 绿色分量
     * @param b 蓝色分量
     * @param flipFlag 是否调转 索引坐标  x,y位置
     * @return NVec 对象
     */
    public NVec xY(final Number x, final Number y,
        final Number r,final Number g, final Number b, final Boolean flipFlag) {
        
        return this.cartesian_point_nvec(x, y, new int[] {r.intValue(),g.intValue(),b.intValue()}, flipFlag);
    }

    /**
     * 笛卡尔坐标 形式的 点结构 <br>
     * 核心函数 <br>
     * 
     * @param x 水平偏移,x 可以为浮点数 
     * @param y 垂直偏移,y 可以为浮点数
     * @param rgb 色彩数组
     * @param flipFlag 是否调转 索引坐标  x,y位置,null 表示采用默认的this.flipFlag的翻转设置。
     * @return NVec 对象,NVec向量有一个优越性就是 它可以进行浮点运算,这对于需要进行 坐标变换的于处理的 点来是非常拥有的。
     */
    public NVec cartesian_point_nvec(final Number x, final Number y,
        final int[]rgb, final Boolean flipFlag) {
        
        // 占位符的点值: x,y not available piont, Integer.MAX_VALUE 表示不可用值 NA.
        final var xy_na_point = point ( Integer.MAX_VALUE,
            Integer.MAX_VALUE, rgb ); // xy 不可用的值
        
        // 生成具有 二次运算能力的NVec, 之所以不使用 NVec.of(point)，是为了保持 住 x,y的浮点数精度。
        // 否则 NVec.of(point)会把小数部分去掉的，所谓为了保持精度这里 采用了 NVec.set 的方式设置x,y
        // 根据 flipFlag 的索引翻转状态, 设置 x,y索引为有效值,  
        return  (flipFlag == null?this.flipFlag:flipFlag) 
            ? NVec.of(xy_na_point).idval_set( 0, y, 1, x ) // x,y 调转顺序,翻转状态
            : NVec.of(xy_na_point).idval_set( 0, x, 1, y ); // x,y 标准顺序,不翻转.
    }
    
    /**
     * 生成极坐标点并进行仿射变换的函数<br>
     * 
     * @param scalex x方向缩放比例
     * @param scaley y方向缩放比例
     * @param offsetx x方向平移量
     * @param offsety y方向平移量
     * @return theta->NVec的带有仿射变换能力的 函数 。采用 theta幅角弧度，生成一个单位向量，然后 进行 affine变换。结果是一个NVec
     */
    public Function<Double,NVec> rhotheta_affine(Number scalex,Number scaley,Number offsetx,Number offsety){
        return theta -> this.rhoTheta(theta).affine(scalex, scaley,offsetx, offsety);
    }
    
    /**
     * 极坐标 形式点：单位向量 (rho,theta) <br>
     * polar_point_nvec 的别名 <br>
     * rho的长度默认为1
     * 
     * @param theta 方向角度
     * @return NVec 对象
     */
    public NVec rhoTheta(final Number theta) {
        
       return this.polar_point_nvec(null, theta);
    }
    
    /**
     * 极坐标 形式点：单位向量(1,theta)
     * 
     * @param theta 方向角度
     * @return NVec 对象
     */
    public NVec polar_point_nvec(final Number theta) {
        
       return this.polar_point_nvec(null, theta);
    }
    
    /**
     * 极坐标 形式点：单位向量 (rho,theta) <br>
     * polar_point_nvec 的别名 <br>
     * 
     * @param rho   矢径长度, null 默认为1
     * @param theta 方向角度
     * @return NVec 对象
     */
    public NVec rhoTheta(final Number rho, final Number theta) {
        
        return this.polar_point_nvec(rho,theta);
    }

    /**
     * 极坐标 形式点：单位向量 (rho,theta)
     * 
     * 核心函数 <br>
     * 
     * @param rho   矢径长度,null 默认为1
     * @param theta 方向角度
     * @return NVec 对象
     */
    public NVec polar_point_nvec(final Number rho, final Number theta) {
        
        final var final_rho = (rho==null?1:rho.doubleValue());
        final var x = final_rho * Math.cos(theta.doubleValue());
        final var y = final_rho * Math.sin(theta.doubleValue());
        
        return this.cartesian_point_nvec(x, y, null, flipFlag);
    }
    
    /**
     * 极坐标 形式点：单位向量 (rho,theta) <br>
     * polar_point_nvec 的别名 <br>
     * 
     * @param rho   矢径长度, null 默认为1
     * @param theta 方向角度
     * @param rgb 色彩数组
     * @return NVec 对象
     */
    public NVec rhoTheta(final Number rho, final Number theta,final int[] rgb) {
        return this.polar_point_nvec(rho, theta, rgb);
    }
    
    /**
     * 极坐标 形式点：单位向量 (rho,theta)
     * 
     * 核心函数 <br>
     * 
     * @param rho   矢径长度,null 默认为1
     * @param theta 方向角度
     * @param rgb 色彩数组
     * @return NVec 对象
     */
    public NVec polar_point_nvec(final Number rho, final Number theta,final int[] rgb) {
        
        final var final_rho = (rho==null?1:rho.doubleValue());
        final var x = final_rho * Math.cos(theta.doubleValue());
        final var y = final_rho * Math.sin(theta.doubleValue());
        
        return this.cartesian_point_nvec(x, y, rgb, flipFlag);
    }
    
    /**
     * 坐标轴反转：翻转 x,y的顺序。 <br>
     * true:第一索引y,第二索引x 即 颜色点向量 [y,x,r,g,b] <br>
     * false:第一索引x,第二索引y 即 颜色点向量 [x,y,r,g,b] <br>
     * @return MatlibCanvas 对象本省便于实现链式编程。
     */
    public MatlibCanvas flip() {
        
        this.flipFlag = !this.flipFlag;
        
        return this;
    }
    
    /**
     * 坐标轴是否被翻转 <br>
     * true:第一索引y,第二索引x 即 颜色点向量 [y,x,r,g,b] <br>
     * false:第一索引x,第二索引y 即 颜色点向量 [x,y,r,g,b] <br>
     * @return 坐标轴的翻转状态
     */
    public Boolean isFlipped(){
        
        return this.flipFlag;
    }

    /**
     * 图像渲染 <br>
     * <br>
     * 本函数不会对图像数据做变换操作。<br><br>
     * 注意：因为图片的高度坐标从从上向下递增，而我们一般的数学习惯 是 坐标轴是从下向上递增的。<br>
     * 所以采用数学坐标绘制的图像,一般需要上下翻转的变换,即 y=height-y才能给予正确显示<br>
     * 数据点的翻转操作可以 在 renderer 回调函数中给予进行.
     * <br>
     * @param sessionCallback 会话操作函数
     * @param width 宽度
     * @param height 高度
     * @param sessionCallback 回调函数
     * @return BufferedImage
     */
    public BufferedImage drawImage(final int width,final int height,
        final Consumer<PenSession> sessionCallback) {
        
        return this.drawImage(width, height, sessionCallback,data->{});
    }

    /**
     * 图像渲染 <br>
     * 核心函数 <br>
     * <br>
     * 注意：因为图片的高度坐标从从上向下递增，而我们一般的数学习惯 是 坐标轴是从下向上递增的。<br>
     * 所以采用数学坐标绘制的图像,一般需要上下翻转的变换,即 y=height-y才能给予正确显示<br>
     * 数据点的翻转操作可以 在 renderer 回调函数中给予进行
     * <br>
     * @param sessionCallback 会话操作函数
     * @param width 宽度
     * @param height 高度
     * @param sessionCallback 回调函数
     * @param renderer 数据渲染操作函数：比如做 图像的上下翻转操作: <br>
     *  data -> data.forEach( e-> e[1] = height-e[1] )
     * @return BufferedImage
     */
    public BufferedImage drawImage(final int width, final int height,
        final Consumer<PenSession> sessionCallback,Consumer<List<int[]>> renderer ) {
        
        final var sess = this.new PenSession(); // 制造一个会话
        sessionCallback.accept(sess);
        sess.render(renderer); // 数据渲染
        
        final var wd = ImageOps.between(0,width);
        final var ht = ImageOps.between(0,height);
        final var imgdata = sess.xyrgbs.stream()
            .filter( e-> wd.test(e[0]) && ht.test(e[1]) ); // 去除无效像素，非法坐标。
        final var image = ImageOps.xyrgbs2bimg(width,height,imgdata);// 制作图片
        sess.reset();// 数据恢复
        
        return image;
    }
    
    /**
     * 图像渲染<br>
     * 
     * 对图像数据做 纵向翻转 以保证  生成的图片内容在视觉上 符合数学习惯。<br>
     * 
     * @param width 宽度
     * @param height 高度
     * @param sessionCallback 会话操作函数
     * @return BufferedImage 图片数据
     */
    public BufferedImage plot(final int width,final int height,
        final Consumer<PenSession> sessionCallback) {
        
        return this.plot(width, height, sessionCallback, null, true);// 调用ImagePlot
    }
    
    /**
     * 图像渲染<br>
     * 
     * 对图像数据做 纵向翻转 以保证  生成的图片内容在视觉上 符合数学习惯。<br>
     * <br>
     * 注意：因为图片的高度坐标从从上向下递增，而我们一般的数学习惯 是 坐标轴是从下向上递增的。<br>
     * 所以采用数学坐标绘制的图像,一般需要上下翻转的变换,即 y=height-y才能给予正确显示<br>
     * 数据点的翻转操作可以 在 renderer 回调函数中给予进行
     * 
     * @param width 宽度
     * @param height 高度
     * @param sessionCallback 会话操作函数
     * @param plotflag 绘图标志,是否调用ImagePlot进行图片显示
     * @return BufferedImage 图片数据
     */
    public BufferedImage plot(final int width,final int height,
        final Consumer<PenSession> sessionCallback, final boolean plotflag) {
        
        return plot(width,height,sessionCallback,null,plotflag);
    }
    
    /**
     * 图像渲染 <br>
     * <br>
     * 注意：因为图片的高度坐标从从上向下递增，而我们一般的数学习惯 是 坐标轴是从下向上递增的。<br>
     * 所以采用数学坐标绘制的图像,一般需要上下翻转的变换,即 y=height-y才能给予正确显示<br>
     * 数据点的翻转操作可以 在 renderer 回调函数中给予进行 <br>
     * 
     * @param width 宽度
     * @param height 高度
     * @param sessionCallback 会话操作函数
     * @param renderer 绘图数据渲染器 <br>
     * 图像数据为 [[x,y,r,g,b]]->{}, 可以 在renderer 对像素点进行调整。 <br>
     * 当renderer 为null, 默认对 图像数据做纵向翻转操作。<br>
     * data -> data.forEach(e->e[1]=height-e[1]) 
     * @param plotflag 绘图标志,是否调用ImagePlot进行图片显示
     * @return BufferedImage 图片数据
     */
    public BufferedImage plot(final int width,final int height,
        final Consumer<PenSession> sessionCallback, 
        final Consumer<List<int[]>> renderer,
        final boolean plotflag) {
        
        final Consumer<List<int[]>> final_renderer = renderer!=null
            ? renderer
            : data -> { // 图像高度数据坐标旋转
                    data.forEach(e->e[1]=height-e[1]); // 上下对调
              }; // 图像渲染器
        final var bufferedImage = this.drawImage(width, height,
            sessionCallback,final_renderer); // drawImage
        if(plotflag) ImagePlot.plot(bufferedImage); // 使用 plotflag 控制是否 采用GUI进行绘图
        
        return bufferedImage;
    }
    
    /**
     * 绘制一条直线 <br>
     * @param <T> 节点序列的元素类型
     * @param x0 开始点  x
     * @param y0 开始点  y
     * @param x1 终止点  x
     * @param y1 终止点  y
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public List<int[]> drawStraightLine(int x0, int y0, int x1, int y1,
        final int[] color,final Boolean flipFlag){
        
        return this.drawStraightLine(x0, y0, x1, y1, 
            (x,y)-> point(x,y,color,flipFlag));
    }
    
    /**
     * 绘制一条直线
     * @param <T> 节点序列的元素类型
     * @param range x 的变化范围
     * @param fx y值函数
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> List<T> drawStraightLine(final Range range, 
        final Function<Double,Double> fx,
        final BiFunction<Double,Double,T> point_renderer) {
        
        final var rng = (range == null ? this.range : range);
        final var aa = rng.startEndS()
            .map(e -> new int[] { e.intValue(), fx.apply(e).intValue() })
            .toArray(int[][]::new);
        
        return this.drawStraightLine(aa[0][0], aa[0][1], 
            aa[1][0], aa[1][1], point_renderer);
    }
    
    /**
     * 绘制一条直线
     * 
     * @param fx y值函数
     * @return 节点序列:[t]
     */
    public List<int[]> drawStraightLine(final Function<Double, Double> fx) {

        return this.drawStraightLine(range, fx, color, flipFlag);
    }

    /**
     * 绘制一条直线
     * 
     * @param range    x 的变化范围
     * @param fx       y值函数
     * @param color    线条颜色
     * @param flipFlag x,y的翻转标记:true,表示翻转
     * @return 节点序列:[t]
     */
    public List<int[]> drawStraightLine(final Range range, 
        final Function<Double, Double> fx, final int[] color,
        final Boolean flipFlag) {

        return this.drawStraightLine(range, fx, (x, y) -> point(x, y, color, flipFlag));
    }
    
    /**
     * 绘制一条直线 <br>
     * 核心函数 <br>
     * 
     * @param <T>            节点序列的元素类型
     * @param x0             开始点 x
     * @param y0             开始点 y
     * @param x1             终止点 x
     * @param y1             终止点 y
     * @param point_renderer 点向量生成函数:(x,y)->t
     * @return 节点序列:[t]
     */
    public <T> List<T> drawStraightLine(int x0, int y0, int x1, int y1,
        final BiFunction<Double, Double, T> point_renderer) {

        final var points = new LinkedList<T>(); // 返回
        bresenham_line(x0, y0, x1, y1, (x, y) -> 
            points.add(point_renderer.apply(x.doubleValue(), y.doubleValue())));

        return points;
    }

    /**
     * 获取主区间范围(自变量:定义域)
     * 
     * @return the range
     */
    public Range getRange() {
        
        return range;
    }

    /**
     * 设置主区间范围(自变量:定义域)
     * 
     * @param range the range to set
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas setRange(final Range range) {
        
        this.globalStack.push(this.range);// 保存以前的range
        this.range = range;
        
        return this;
    }

    /**
     * 设置主区间范围
     * 
     * @param start 开始位置
     * @param end 结束位置
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas setRange(final Number start,final Number end) {
        
        this.setRange(new Range(start,end));
        
        return this;
    }

    /**
     * 从堆栈中弹出 最近一次所保存range并将它设置为主区间范围,即 区间范围的回退 <br>
     * 
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas popRange() {
        
        if(!this.globalStack.empty(Range.class)) {
            this.setRange(this.globalStack.pop(Range.class));
        }//if
        
        return this;
    }

    /**
     * 获取绘图画布的默认画笔色Color
     * @return the color
     */
    public int[] getColor() {
        
        return color;
    }

    /**
     * 设置绘图画布的默认画笔色Color
     * @param color the color to set
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas setColor(int[] color) {
        
        this.globalStack.push(this.color);
        this.color = color;
        
        return this;
    }

    /**
     *  从堆栈中弹出 最近一次所保存Color并将它设置为主区间范围,即 绘图画布的默认画笔色Color 的回退 <br>
     *  
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas popColor() {
        
        if(!this.globalStack.empty(int[].class)) {
            this.setColor(this.globalStack.pop(int[].class));
        }//if
        
        return this;
    }

    /**
     * 画布重置,即 重设画布为出厂状态，<br>
     * 清空全局堆栈(保存状态过程信息 如 默认绘图色 Color,主区间范围 Range[自变量定义域] 等 的设置 已便于处理  必要的 回退请求 的数据结构) <br>
     * 所以reset只收不做绘图状态回退操作的。<br>
     *  
     * @return MatlibCanvas 以便于实现链式编程
     */
    public MatlibCanvas reset() {
        
        globalStack.reset(Range.class, 
            s->{while(!s.empty())MatlibCanvas.this.setRange(s.pop());});
        globalStack.reset(int[].class, 
            s->{while(!s.empty())MatlibCanvas.this.setColor(s.pop());});
        
        // 清空全局堆栈 
        globalStack.clear();
        
        return this;
    }

    /**
     * 画笔会话 <br>
     * 
     * @author gbench
     */
    public class PenSession {
        
        /**
         * 绘制一条曲线
         * 
         * @param fxs 曲线族函数
         * @return PenSession 便于实现链式编程
         */
        @SafeVarargs
        final public PenSession drawLines(final Function<Double, Double> ... fxs) {
            
            return this.drawLines((Range)null, fxs);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param start 开始位置 inclusive
         * @param end 结束位置   exclusive
         * @param fxs 曲线族函数
         * @return PenSession 便于实现链式编程
         */
        @SafeVarargs
        final public PenSession drawLines(final Number start,final Number end,
            final Function<Double, Double> ... fxs) {
            
            final var range = new Range(start,end);
            this.drawLines(range, fxs);
            
            return this;
        }
        
        /**
         * 绘制一条曲线 <br>
         * 核心函数 <br>
         * 
         * @param range x的区间范围
         * @param fxs 曲线族函数
         * @return PenSession 便于实现链式编程
         */
        @SafeVarargs
        final public PenSession drawLines(final Range range,
            final Function<Double, Double> ... fxs) {
            
            Arrays.stream(fxs).forEach(fx->this.drawLine(range,fx));
            
            return this;
        }
        
        /**
         * 绘制一条曲线,drawLineX的别名
         * 
         * @param fx y值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Function<Double, Double> fx) {
            
            return this.drawLineX(fx);
        }
        
        /**
         * 绘制一条曲线:
         * 
         * @param fx y值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLineX(final Function<Double, Double> fx) {
            
            return this.drawLine((Range)null,fx,(int[])null,false);
        }
        
        /**
         * 反函数/反转绘制<br>
         * 绘制一条曲线:反转绘制, 按照 即反函数的方式进行绘制
         * 
         * @param fy x值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLineY(final Function<Double, Double> fy) {
            
            return this.drawLine((Range)null,fy,(int[])null,true);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param range x的区间范围
         * @param fx y值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Range range,
            final Function<Double, Double> fx) {
            
            return this.drawLine(range,fx,null,null);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param start 开始位置 inclusive
         * @param end 结束位置   exclusive
         * @param fx y值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Number start,final Number end,
            final Function<Double, Double> fx) {
            
            return this.drawLine(start,end,fx,(int[])null);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param fx y值函数
         * @param color rgb颜色
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Function<Double, Double> fx,
            final int[] color) {
            
            return this.drawLine(null,fx,color,(Boolean)null);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param start 开始位置 inclusive
         * @param end 结束位置   exclusive
         * @param fx y值函数
         * @param color rgb颜色
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Number start,final Number end,
            final Function<Double, Double> fx,final int[] color) {
            
            return this.drawLine(new Range(start,end),fx,color,(Boolean)null);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param fx y值函数
         * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Function<Double, Double> fx,
            final Boolean flipFlag) {
           
            return this.drawLine((Range)null,fx,(int[])null,flipFlag);
        }
        
        /**
         * 绘制一条曲线
         * @param range x的区间范围
         * @param fx y值函数
         * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Range range,
            final Function<Double, Double> fx,final Boolean flipFlag) {
            
            return this.drawLine(null,fx,null,flipFlag);
        }
        
        /**
         * 绘制一条曲线
         * 
         * @param range x的区间范围
         * @param fx y值函数
         * @param color rgb曲线颜色
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Range range,
            final Function<Double, Double> fx, final int[] color) {
            
            return this.drawLine(range,fx,color,(Boolean)null);
        }
        
        /**
         * 绘制一条曲线,drawLineX的别名
         * 
         * @param fx y值函数
         * @param color 线条颜色 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final Function<Double,Double> fx) {
            
            this.drawStraightLine(null, fx, null, null);
            
            return this;
        }

        /**
         * 绘制一条曲线,drawLineX的别名
         * 
         * @param range x 的变化范围
         * @param fx y值函数 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final Range range,
            final Function<Double,Double> fx) {
            
            this.drawStraightLine(range, fx, null, null);
            
            return this;
        }
        
        /**
         * 绘制一条曲线,drawLineX的别名
         * 
         * @param range x 的变化范围
         * @param fx y值函数
         * @param color 颜色 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final Function<Double,Double> fx,
            final int []color) {
            
            this.drawStraightLine(null, fx, color, null);
            
            return this;
        }

        /**
         * 绘制一条曲线,drawLineX的别名
         * 
         * @param range x 的变化范围
         * @param fx y值函数
         * @param color 线条颜色 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final Range range,
            final Function<Double,Double> fx, final int[] color) {
            
            this.drawStraightLine(range, fx, color, null);
            
            return this;
        }

        /**
         * 绘制一条曲线,drawLineX的别名 <br>
         * 
         * @param x0 开始点  x
         * @param y0 开始点  y
         * @param x1 终止点  x
         * @param y1 终止点  y
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final int x0, final int y0, 
            final int x1, final int y1) {
            
            return this.drawStraightLine(x0, y0, x1, y1, color, flipFlag);
        }
        
        /**
         * 绘制一条曲线,drawLineX的别名 <br>
         * 
         * @param x0 开始点  x
         * @param y0 开始点  y
         * @param x1 终止点  x
         * @param y1 终止点  y
         * @param color 颜色
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final int x0, final int y0, 
            final int x1, final int y1, final int[] color) {
            
            return this.drawStraightLine(x0, y0, x1, y1, color, flipFlag);
        }
        
        /**
         * 绘制一条曲线,drawLineX的别名 <br>
         * 核心函数 <br>
         * @param x0 开始点  x
         * @param y0 开始点  y
         * @param x1 终止点  x
         * @param y1 终止点  y
         * @param color 线条颜色
         * @param flipFlag x,y的翻转标记:true,表示翻转 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final int x0, final int y0, 
            final int x1, final int y1, int[] color,Boolean flipFlag) {
            
            this.xyrgbs.addAll(MatlibCanvas.this
                .drawStraightLine(x0,y0,x1,y1, color, flipFlag));
            
            return this;
        }


        /**
         * 绘制一个点 <br>
         * 
         * @param fx y值函数
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoint(final Number x,final Number y) {
            
            return this.drawPoints(()->Arrays.asList(MatlibCanvas.this.point(x, y)));
        }
        
        /**
         * 绘制一组点 <br>
         * 点集列表<br>
         * 
         * @param points 点集生成函数,每个点的 向量式 数格式为 : [x,y,r,g,b]
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoints(final Supplier<List<int[]>> points) {
            
            return this.drawPoints(points.get());
        }
        
        /**
         * 绘制一组点 <br>
         * 点集流<br>
         * 
         * @param points 点集流 ,每个点的 向量式 数格式为 : [x,y,r,g,b],点元素的类型为 NVec结构
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoints(final Stream<NVec> points) {
            
            return this.drawPoints(points.map(NVec::ints).collect(Collectors.toList()));
        }
        
        /**
         * 绘制一组点 <br>
         * 点集流,,带有点集变换功能<br>
         * 
         * @param points 点集流 ,每个点的 向量式 数格式为 : [x,y,r,g,b],点元素的类型为 NVec结构
         * @param transformer 点集的变换函数 [nvec]->[nvec],5 x n
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoints(final Stream<NVec> points,
            final Function<DataMatrix<Double>,DataMatrix<Double>> transformer) {
                
            return this.drawPoints(transformer.apply(NVec.matrix_columns(points)).colS()
                    .map(NVec::new).map(NVec::ints)
                    .collect(Collectors.toList()));
        }
        
        /**
         * 绘制一些列点
         * @param points 点集合, 点是  NVec结构向量
         * @param transformer 点变换 函数 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoints2(final Stream<NVec> points,
            final Function<Stream<NVec>,List<int[]>> transformer) {
                
            return this.drawPoints(transformer.apply(points));
        }
        
        /**
         * 绘制一些列点
         * @param <T> 预处理器的 结果类型
         * @param points 点集合, 点是  NVec结构向量
         * @param preprocessor 预处理器的 结果类型
         * @param transformer 点变换 函数 
         * @return PenSession 便于实现链式编程
         */
        public <T> PenSession drawPoints2(final Stream<NVec> points,final Function<Stream<NVec>,T> preprocessor,
            final Function<T,List<int[]>> transformer) {
                
            return this.drawPoints(transformer.apply(preprocessor.apply(points)));
        }
        
        /**
         * 绘制一组点 <br>
         * 点集流,带有点集变换功能<br>
         * 
         * @param points 点集流 ,每个点的 向量式 数格式为 : [x,y,r,g,b],点元素的类型为 NVec结构
         * @param transformer 点集的变换函数 [nvec]->[nvec]
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Function<Double, Double> fx,
            final Function<DataMatrix<Double>,DataMatrix<Double>> transformer) {
        
            final var px = NVec.matrix_columns(MatlibCanvas.this.drawLine(fx).map(NVec::new));// 原始数据
            //System.out.println(px);
            
            final var tx = transformer.apply(px); // 变换后的数据
            //System.out.println(tx);
            
            return this.drawPoints(tx.colS().map(NVec::new).map(NVec::ints)
                .collect(Collectors.toList()));
        }
        
        /***************************************************
         * 
         * 核心函数区域
         * 
         ***************************************************/
        
        /**
         * 绘制一条曲线 <br>
         * 核心函数 <br>
         * 
         * @param range x的区间范围
         * @param fx y值函数
         * @param color rgb曲线颜色
         * @param flipFlag 是否反转坐标轴，flipFlag 是否颠倒 坐标x,y次序
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawLine(final Range range,final Function<Double, Double> fx, 
            final int[] color, final Boolean flipFlag) {
            
            this.xyrgbs.addAll(MatlibCanvas.this.drawLine2(range,fx,color,flipFlag));
            
            return this;
        }

        /**
         * 绘制一条曲线,drawLineX的别名 <br>
         * 核心函数 <br>
         * @param range x 的变化范围
         * @param fx y值函数
         * @param color 线条颜色
         * @param flipFlag x,y的翻转标记:true,表示翻转 
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawStraightLine(final Range range,
            final Function<Double,Double> fx, final int[] color, final Boolean flipFlag) {
            
            this.xyrgbs.addAll(MatlibCanvas.this
                .drawStraightLine(range, fx, color, flipFlag));
            
            return this;
        }

        /**
         * 绘制一组点 <br>
         * 核心函数<br>
         * 
         * @param points 点集, 每个点的 向量式 数格式为 : [x,y,r,g,b]
         * @return PenSession 便于实现链式编程
         */
        public PenSession drawPoints(final List<int[]> points) {
            
            this.xyrgbs.addAll(points);
            
            return this;
        }
        
        /**
         * 打印显示输出
         * @param flag 是否在err上输出
         * @return xyrgbs
         */
        public List<int[]> dump(final boolean flag) {
            
            if (flag) {
                this.xyrgbs.forEach(e -> {
                    System.err.println(ImageOps.box2list(e));
                });
            }
            
            return this.xyrgbs;
        }
        
        /**
         * 设置区间
         * @param start inclusive
         * @param end exclusive
         * @return PenSession
         */
        public PenSession setRange(final Number start, final Number end) {
            
            return this.setRange(new Range(start,end));
        }
        
        /**
         * 设置区间
         * @param range
         * @return PenSession
         */
        public PenSession setRange(final Range range) {
            
            stack.push( MatlibCanvas.this.getRange());
            MatlibCanvas.this.setRange(range);
            
            return this;
        }
        
        /**
         * 恢复区间
         * @return PenSession
         */
        public PenSession resetRange() {
            
            if(stack.empty(Range.class)) {
                System.err.println("range stack is empty");
            }else {
                MatlibCanvas.this.setRange(stack.pop(Range.class));
            }
            
            return this;
        }
        
        /**
         * 设置颜色
         * @param color 设置前景颜色
         * @param r 红色
         * @param g 绿色
         * @param b 蓝色
         * @return PenSession
         */
        public PenSession setColor(int r,int g,int b) {
            
            return this.setColor(new int[] {r%256,g%256,b%256});
        }

        /**
         * 设置区间
         * @param color 画笔颜色
         * @return PenSession
         */
        public PenSession setColor(final int[] color) {
            
            stack.push(MatlibCanvas.this.getColor());
            MatlibCanvas.this.setColor(color);
            
            return this;
        }
        
        /**
         * 恢复区间
         * @return PenSession
         */
        public PenSession resetColor() {
            
            if(stack.empty(int[].class)) {
                System.err.println("color stack is empty");
            }else {
                MatlibCanvas.this.setColor(stack.pop(int[].class));
            }
            
            return this;
        }
        
        /**
         * MatlibCanvas 当前的画布对象
         * @return MatlibCanvas
         */
        public MatlibCanvas getCanvas() {
            
            return MatlibCanvas.this;
        }

        /**
         * 打印显示输出
         * @return
         */
        public List<int[]> dump() {
            
            return dump(true);
        }
        
        /**
         * 会话清空
         */
        public void reset() {
            
            stack.reset(Range.class, 
                s->{while(!s.empty())MatlibCanvas.this.setRange(s.pop());});
            stack.reset(int[].class, 
                s->{while(!s.empty())MatlibCanvas.this.setColor(s.pop());});
            stack.clear();
            xyrgbs.clear();
        }
        
        /**
         * 缓存中的数据渲染 <br>
         * 比如做好一些坐标变换的操作。
         * @return PenSession
         */
        public PenSession render(Consumer<List<int[]>> renderer) {
            
            renderer.accept(this.xyrgbs);
            
            return this;
        }
        
        private List<int[]> xyrgbs = new LinkedList<>(); // 色彩向量
        private MultipleStack stack = new MultipleStack(); // 回退stack;
        
    }
    
    /**
     * 这是一个多类型的堆栈。<br>
     * 
     * @author gbench
     */
    public class MultipleStack {
        
        /**
         * 堆栈数据检查
         * @param obj 压入堆栈的元素
         * @return MultipleStack 本身 以保证 链式编程
         */
        public MultipleStack push(final Object obj) {
            
            if(obj==null)return this;
            final var cls = obj.getClass();
            final var stack = (Stack<Object>)stacks.computeIfAbsent(cls, e->new Stack<Object>());
            stack.push(obj);
            
            return this;
        }
        
        /**
         * 弹出堆栈元素
         */
        public <T> T pop(final Class<T> clazz) {
            
            final var stack = this.getStack(clazz);
            if(stack==null)return null;
            
            return stack.pop();
        }
        
        /**
         * 堆栈空状态检查
         * @param <T>
         * @param clazz
         * @return 判断堆栈clazz是否为空
         */
        public <T> boolean empty(Class<T> clazz) {
            
            if(this.getStack(clazz)==null)return true;
            
            return this.getStack(clazz).empty();
        }
        
        /**
         * 数据 重置
         * @param <T> 数据重置
         * @param clazz 堆栈的元素类型
         * @param cs 回调函数
         * @return MultipleStack 本身 以保证 链式编程
         */
        public <T> MultipleStack reset(final Class<T> clazz,final Consumer<Stack<T>>cs) {
            
            final var stack = this.getStack(clazz);
            
            if(stack!=null) {
                cs.accept(stack);
            }else {
                System.err.println(clazz.getSimpleName()+" 的堆栈数据为空");
            }// if
            
            return this;
        }
        
        /**
         * 获取指定类型的堆栈
         * @param <T> 堆栈元素的类型
         * @param clazz 堆栈的元素类型
         * @return 堆栈
         */
        @SuppressWarnings("unchecked")
        public <T> Stack<T> getStack(final Class<T> clazz){
            
            return (Stack<T>)this.stacks.get(clazz);
        }
        
        /**
         * 清空整个堆栈
         * @return MultipleStack 本身 以保证 链式编程
         */
        public MultipleStack clear() {
            
            stacks.clear();
            
            return this;
        }
        
        private Map<Class<?>,Stack<Object>> stacks = new HashMap<>(); // 堆栈集合
    }
    
    /**
     * 索引键 与 索引值 <br>
     * 这是一个多维度的键值结构(KVPair)<br>
     * 
     * @author gbench
     *
     * @param <K> 索引键的类型
     * @param <V> 值类型的类型
     * @param <SELF> 本身类型：当前类的实际类型，这是一种泛型化实现的向前兼容的设计（技巧）
     */
    public static class IdxValPair<K,V,SELF> {
        
        /**
         * 索引与值
         * @param index 索引，指定号的维度
         * @param value 值
         */
        public IdxValPair(final K index, final V value){
            
            this.index = index;
            this.value = value;
        }
        
        /**
         * 获取索引值
         * @return the index
         */
        public K getIndex() {
            
            return index;
        }
        
        /**
         * @param index the index to set
         * @return 返回当前对象本身便于实现链式编程
         */
        public SELF setIndex(final K index) {
            
            this.index = index;
            
            return this.self();
        }
        
        /**
         * @return the value
         */
        public V getValue() {
            
            return value;
        }
        
        /**
         * @param value the value to set
         * @return 返回当前对象本身便于实现链式编程
         */
        public SELF setValue(final V value) {
            
            this.value = value;
            
            return this.self();
        }
        
        /**
         * 索引键
         * @return 索引键
         */
        public K idx() {
            
            return this.getIndex();
        }
        
        /**
         * 索引值
         * @return 索引值
         */
        public V val() {
            
            return this.getValue();
        }
        
        /**
         * 获取 索引键 的类型类
         * @return 索引键 的类型类
         */
        @SuppressWarnings("unchecked")
        public Class<K> idxClass(){
            
            if(this.index==null)return null;
            
            return (Class<K>)index.getClass();
        }
        
        /**
         * 获取 值 的类型类
         * @return 值 的类型类
         */
        @SuppressWarnings("unchecked")
        public Class<V> valClass(){
            
            if(this.value==null)return null;
            
            return (Class<V>)value.getClass();
        }
        
        /**
         * 返回当前对象本身。这是泛型，向前兼容的设计实现。
         * @return 返回当前对象本身 即 this
         */
        @SuppressWarnings("unchecked")
        public SELF self() {
            
            return (SELF)this;
        }
        
        /**
         * 应用函数技术
         * @param <U> 结果类型
         * @param evaluator 索引键值计算器:(index,value)->u
         * @return U 类型的结果
         */
        public <U> U evaluate(final BiFunction<K,V,U> evaluator) {
            
            return evaluator.apply(index, value);
        }
        
        /**
         * 递延计算 函数
         * @param <U> 结果类型
         * @param bifunc 索引键值计算器
         * @return 一个U值的 supplier
         */
        public <U> Supplier<U> lazyEval(final BiFunction<K,V,U> evaluator) {
            
            return () -> evaluator.apply(index, value);
        }
        
        /**
         * 通过一个 二元回调函数 对 集合对象采用 根据index进行赋值 
         * <br>
         * 用法示例:<br> 
         * V[] vv = ... // vv 是一个数组对象 <br>
         * ivp.assignTo((k,v)->vv[k]=v); <br>
         * <br>
         * @param assign 被回调的函数
         * @return 返回当前对象本身便于实现链式编程
         */
        public SELF assignTo(final BiConsumer<K,V> assign) {
            
            assign.accept(index, value);
            
            return this.self();
        }
        
        /**
         * value 映射:v->u
         * @param <U> 结果值得类型
         * @param mapper  v->u
         * @return U  结果类型
         */
        public <U> U map( Function<V,U> mapper ) {
            
            return mapper.apply(this.value);
        }
        
        /**
         * 映射:(index,value)->u
         * @param <U> 结果值得类型
         * @param mapper 映射器 v->u
         * @return U  结果类型
         */
        public <U> U map( BiFunction<K,V,U> mapper ) {
            
            return mapper.apply(this.index,this.value);
        }
        
        /**
         * 数据格式化
         */
        @Override
        public String toString() {
            return "( "+this.index+" , "+this.value+" )";
        }
        
        /**
         * 获取值类型
         * @param <T> idxvalues 列表元素的类型
         * @param <K> 索引键类型
         * @param <V> 索引值类型
         * @param <SELF> 基泛型的派生类型额前向引用
         * @param idxvalues 索引键-值列表
         * @return 索引值类型的Optional
         */
        public static <K,V,SELF,T extends IdxValPair<K,V,SELF>> Optional<Class<V>> 
            getValClazz( final List<T> idxvalues ){
            
            return idxvalues.stream().map(e->e.valClass())
                .dropWhile(e->e==null).findFirst();
        }
        
        /**
         * 获取索引值列表的 索引键流
         * @param <T> idxvalues 列表元素的类型
         * @param <K> 索引键类型
         * @param <V> 索引值类型
         * @param <SELF> 基泛型的派生类型额前向引用
         * @param idxvalues 索引键-值列表
         * @return 索引值列表idxvalues的 索引键流
         */
        public static <K,V,SELF,T extends IdxValPair<K,V,SELF>> Stream<K>
            idxStream( final List<T> idxvalues ){
            
            return idxvalues.stream().map(e->e.index);
        }
        
        /**
         * 获取索引值列表的 索引值流
         * @param <T> idxvalues 列表元素的类型
         * @param <K> 索引键类型
         * @param <V> 索引值类型
         * @param <SELF> 基泛型的派生类型额前向引用
         * @param idxvalues 索引键-值列表
         * @return 索引值列表idxvalues的 索引值流
         */
        public static <K,V,SELF,T extends IdxValPair<K,V,SELF>> Stream<V>
            valStream( final List<T> idxvalues ){
            
            return idxvalues.stream().map(e->e.value);
        }
        
        /**
         * 数据分析，将源数据列表tt做索引键值分析, 提取索引键值结构IVP并生成IVP结构的数据列表
         * @param <T> tt 源数据列表中的元素类型
         * @param <K> 索引键类型
         * @param <V> 索引值类型
         * @param <SELF> 基泛型的派生类型额前向引用
         * @param <IVP> IdxValPair的派生类型
         * @param tt 索引键-值列表
         * @param indexer 索引生成器:t->k
         * @param valueer 值生成器:t->v
         * @param ivp_creator IVP的生成器:(index,value)->ivp
         * @param ivp_regulator 会在最终提交 ivp值对象之间进行回调，所以可以 在ivp_callback中做一点ivp的调节操作。 
         * @return IVP 类型的流
         */
        public static <K,V,SELF,IVP extends IdxValPair<K,V,SELF>,T> Stream<IVP> analyze (
            final List<T> tt,
            final Function<T,K> indexer,
            final Function<T,V> valueer,
            final BiFunction<K,V,IVP> ivp_creator,
            final Consumer<IVP> ivp_regulator ){
            
            return analyze(tt,indexer,valueer,ivp_creator, ivp -> { 
                ivp_regulator.accept(ivp); 
                return ivp; 
            });
        }
        
        /**
         * 数据分析，将源数据列表tt做索引键值分析, 提取索引键值结构IVP,然后对IVP应用 mapper获取目标结构U的数据列表
         * 核心函数 <br>
         * @param <T> tt 源数据列表中的元素类型
         * @param <K> 索引键类型
         * @param <V> 索引值类型
         * @param <SELF> 基泛型的派生类型额前向引用
         * @param <IVP> IdxValPair的派生类型
         * @param <U> 发挥结果的元素类型
         * @param tt 索引键-值列表
         * @param indexer 索引生成器:t->k
         * @param valueer 值生成器:t->v
         * @param ivp_creator IVP的生成器:(index,value)->ivp
         * @param mapper IVP 到 U的变换函数:ivp->u 
         * @return U 类型的流
         */
        public static <K,V,SELF,IVP extends IdxValPair<K,V,SELF>,T,U> Stream<U> analyze ( 
             final List<T> tt, 
             final Function<T,K> indexer,
             final Function<T,V> valueer,
             final BiFunction<K,V,IVP> ivp_creator,
             final Function<IVP,U> mapper ){
            
             return tt.stream()
                .map( e -> ivp_creator.apply( indexer.apply(e), valueer.apply(e) ) )
                .map( mapper );
        }
        
        /**
         * 索引键
         */
        protected K index;
        
        /**
         *  索引值
         */
        protected V value;
    }
    
    /**
     * 索引与值 <br>
     * 这是对KVPair一种特化的实现,Key 特化为 int[] <br>
     * 
     * @author gbench
     *
     * @param <V> 值的类型
     */
    public static class IndexValuePair<V> extends IdxValPair<int[],V,IndexValuePair<V>> {
        
        /**
         * 索引与值
         * @param index 索引，指定号的维度
         * @param value 值
         */
        public IndexValuePair(final int[] index, final V value){
            
            super(index,value);
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[][][][][][] vv) {
            
            vv[index[0]][index[1]][index[2]][index[3]][index[4]][index[5]] = value;
            
            return this;
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[][][][][] vv) {
            
            vv[index[0]][index[1]][index[2]][index[3]][index[4]] = value;
            
            return this;
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[][][][] vv) {
            
            vv[index[0]][index[1]][index[2]][index[3]] = value;
            
            return this;
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[][][] vv) {
            
            vv[index[0]][index[1]][index[2]] = value;
            
            return this;
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[][] vv) {
            
            vv[index[0]][index[1]] = value;
            
            return this;
        }
        
        /**
         * 把当前的Index2Value复制到uu对应的元素位置。
         * 
         * @param uu 矩阵元素
         * @return Index2Value 方便实现链式编程
         */
        public IndexValuePair<V> assignTo(final V[] vv) {
            
            vv[index[0]] = value;
            
            return this;
        }
        
        /**
         * 数据格式化
         */
        @Override
        public String toString() {
            
            return "( ["+Arrays.stream(this.index).mapToObj(e->e+"").collect(Collectors.joining(","))+"] , "+this.value+" )";
        }
        
        /**
         * 索引与值
         * @param <V> 值类型
         * @param index 索引，指定号的维度
         * @param value 值
         * @return IndexValue
         */
        public static <V> IndexValuePair<V> of(final int[] index, final V value){
            
            return new IndexValuePair<>(index,value);
        }
        
    }
    
    /**
     * 区间范围 是空间的构成单元 <br>
     * 代表了特定概念（关键属性，特征）的数量维度 <br>
     * 多个 维度可以  组合在一起 共同的 张成span出一个 多维空间 ,这是是设计Range的初始目标。<br>
     * 我们可在Range 所张成的 空间(采样点数据流)的基础之上进行  点概念 即 向量的构造，<br>
     * 进而 获得 一个有意义  数据结构(空间) <br>
     * 具体的如何组织 请看 span方法。<br>
     * 
     * <br>
     * 区间范围[start,end) 采样点数据流 的控制结构 即 区间类Range<br>
     * 
     * 区间类Range 的一个有用的用途就是用于 定义 区间范围 采样点 结构, 简称 采样点。 <br>
     * 采样点,这是一个函数化的  for循环 控制结构。可以用来模拟生成 如下的 采样点序列。
     * [start,start+step,start+2*step,...,end)   <br>
     * 
     * @author gbench
     */
    public static class Range {
        
        /**
         * 无限循环 结构:0,1,2,...,Double.MAX_VALUE,... <br>
         * 区间对象(步长默认为1)<br>
         * start 开始数量 默认为 0,inclusive <br>
         * end 截止数量  默认为  Double.MAX_VALUE exclusive <br>
         * 单内部处理 示  Double.MAX_VALUE 为无限大，即 当出现  Double.MAX_VALUE<br>
         * 所以此时生成的流可以被视作一个 for(true){}的循环来使用。
         */
        public Range(){
            
           this(Double.MAX_VALUE);
        }
        
        /**
         * 拷贝构造一个区间对象
         * 
         * @param points 采样点序列 直接引用
         */
        public Range(final List<Double> points) {
            
            this.points = points;
        }
        
        /**
         * 拷贝构造一个区间对象
         * 
         * @param range 被拷贝的区间对象
         */
        public Range(final Range range){
            
           this(range.start, range.end,range.step);
           this.points = range.points;
           this.start_supplier = range.start_supplier;
           this.predicate_hasnext = range.predicate_hasnext;
           this.tri_nexter = range.tri_nexter;
        }
        
        /**
         * 区间对象(步长默认为1) <br>
         * start 开始数量 默认为0,inclusive <br>
         * @param end 截止数量 exclusive
         */
        public Range(final Number end){
            
           this(0, end);
        }
        
        /**
         * 区间对象(步长默认为1)
         * @param start 开始数量 inclusive
         * @param end 截止数量 exclusive
         */
        public Range(final Number start,final Number end){
            
            this(start,end,1);
        }
        
        /**
         * 区间对象
         * @param start 开始数量 inclusive
         * @param end 截止数量 exclusive
         * @param end 补偿的结对值，负数会自动取绝对值
         */
        public Range(final Number start, final Number end, final Number step){
            
            this.start = start;
            this.end = end;
            final var sign = start.doubleValue()<end.doubleValue()?1d:-1d; // 步长符号
            this.step = sign*Math.abs(step.doubleValue());
        }
        
        /**
         * 开始点 <br>
         * 返回浮点类型的开始点
         * @return the start
         */
        public Double start() {
            
            return this.getStart();
        }
        
        /**
         * 开始点 <br>
         * @return the start
         */
        public Double getStart() {
            
            return start.doubleValue();
        }
        
        /**
         * 设置开始点 <br>
         * @param start the start to set
         * @return Range 本身以方便进行链式编程
         */
        public Range setStart(Number start) {
            
            this.start = start;
            
            return this;
        }
        
        /**
         * 结束点 <br> 
         * 不包含 <br>
         * 返回浮点类型的结束点
         * @return the end
         */
        public Double end() {
            
            return end.doubleValue();
        }
        
        /**
         * 结束点 <br> 
         * @return the end
         */
        public Number getEnd() {
            
            return end;
        }
        
        /**
         * 设置 结束点 <br> 
         * @param end the end to set
         * @return Range 本身以方便进行链式编程
         */
        public Range setEnd(final Number end) {
            
            this.end = end;
            
            return this;
        }
        
        /**
         * 采样间隔<br>
         * 返回浮点类型的采样间隔
         * @return the step
         */
        public Double step() {
            
            return step.doubleValue();
        }
        
        /**
         * 采样间隔<br>
         * @return the step
         */
        public Number getStep() {
            
            return step;
        }

        /**
         * 设置 采样间隔<br>
         * @param step the step to set
         * @return Range 本身以方便进行链式编程
         */
        public Range setStep(Number step) {
            
            this.step = step;
            
            return this;
        }
        
        /**
         * Double类型的 采样点序列 数据流
         * 当 end == =Double.MAX_VALUE 时候 视为 无限循环
         * @return Double类型的数据流
         */
        public Stream<Double> dblStream(){
            
            return this.dblStream(tri_nexter);
        }
        
        /**
         * Double类型的 采样点序列 数据流
         * 当 end == =Double.MAX_VALUE 时候 视为 无限循环
         * @param tri_nexter 步长调节器
         * @return Double类型的数据流
         */
        public Stream<Double> dblStream(final TriFunction<Integer,Double,Double,Double> tri_nexter){
            
            if( this.points!=null && this.points.size()>0) { // 静态采样点
                return this.points.stream();
            }else { //动态采样点
                final var ai = new AtomicInteger(0); // 序号生成器
                return Stream.iterate(start_supplier.get(), // seeds
                    i-> predicate_hasnext.test(ai.get(), i), // hasNext
                    i-> tri_nexter.apply(ai.getAndIncrement(),i,step.doubleValue())); // next
            }// if
        }
        
        /**
         * Integer 类型的  采样点序列 数据流
         * @return Integer类型的数据流
         */
        public Stream<Integer> intStream(){
            
            return this.dblStream().map(e->e.intValue());
        }
        
        /**
         * 开始元素与结束 元素构成的流
         * @return [start,end] 两个元素的流。
         */
        public Stream<Double> startEndS(){
            
            return Stream.of(this.start.doubleValue(),this.end.doubleValue());
        }
        
        /**
         * 转换成  Double[] 数组 <br>
         * dblA的别名 <br> 
         * @return double 数组
         */
        public double[] toArray() {
            
            return this.dblA();
        }
        
        /**
         * 转换成  Double[] 数组 
         * @return Double 数组
         */
        public Double[] toArray2() {
            
            return this.dblStream().toArray(Double[]::new);
        }
        
        /**
         * start 和 end 进行方向调换，更改step的正负号
         * @return [end,star) 的翻转范围 
         */
        public Range reverse() {
            
            return new Range(this.end,this.start,-this.step.doubleValue());
        }

        /**
         * int类型的   采样点序列 数据流
         * @return int 类型的数据流
         */
        public IntStream intS(){
            
            return dblStream().mapToInt(e->e.intValue());
        }

        /**
         * long 类型的   采样点序列 数据流
         * @return long 类型的数据流
         */
        public LongStream lngS(){
            
            return dblStream().mapToLong(e->e.longValue());
        }

        /**
         * double 类型的   采样点序列 数据流
         * @return double 类型的数据流
         */
        public DoubleStream dblS(){
            
            return dblStream().mapToDouble(e->e.doubleValue());
        }

        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据列表
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型数据流
         */
        public <T> List<T> intL(final Function<Integer,T> mapper){
            
            return this.mapInt(mapper).collect(Collectors.toList());
        }
        
        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 列表
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型数据流
         */
        public <T> List<T> lngL(final Function<Long,T> mapper){
            
            return this.mapLong(mapper).collect(Collectors.toList());
        }
        
        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 列表
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型数据流
         */
        public <T> List<T> dblL(final Function<Double,T> mapper){
            
            return this.mapDouble(mapper).collect(Collectors.toList());
        }
        
        /**
         * int类型的   采样点 数组
         * @return int 类型的数组
         */
        public int[] intA(){
            
            return this.intS().toArray();
        }

        /**
         * long 类型的   采样点 数组
         * @return long 类型的 数组
         */
        public long[] lngA(){
            
            return this.lngS().toArray();
        }

        /**
         * double 类型的   采样点 数组
         * @return double 类型数组
         */
        public double[] dblA(){
            
            return this.dblS().toArray();
        }
        
        /**
         * Integer 类型的   采样点 数组
         * @return Integer 类型数组
         */
        public Integer[] intA2(){
            
            return this.intS().boxed().toArray(Integer[]::new);
        }
        
        /**
         * long 类型的   采样点 数组
         * @return Long 类型数组
         */
        public Long[] lngA2(){
            
            return this.lngS().boxed().toArray(Long[]::new);
        }
        
        /**
         * Double 类型的   采样点 数组
         * @return Double 类型数组
         */
        public Double[] dblA2(){
            
            return this.dblS().boxed().toArray(Double[]::new);
        }
        
        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 数组
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型的数组
         */
        @SuppressWarnings("unchecked")
        public <T> T[] dblA2(final Function<Double,T> mapper){

            final var ar = new AtomicReference<Class<T>>();
            return this.mapDouble(e->{
                final var t = mapper.apply(e);
                if(t!=null && ar.get()==null)ar.set((Class<T>)t.getClass());
                return t;
            }).toArray(n->(T[])Array.newInstance(ar.get(), n));
        }
        
        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 数组
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型的数组
         */
        @SuppressWarnings("unchecked")
        public <T> T[] intA2(final Function<Integer,T> mapper){

            final var ar = new AtomicReference<Class<T>>();
            return this.mapInt(e->{
                final var t = mapper.apply(e);
                if(t!=null && ar.get()==null)ar.set((Class<T>)t.getClass());
                return t;
            }).toArray(n->(T[])Array.newInstance(ar.get(), n));
        }
        
        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 数组
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型的数组
         */
        @SuppressWarnings("unchecked")
        public <T> T[] lngA2(final Function<Long,T> mapper){
            
            final var ar = new AtomicReference<Class<T>>();
            return this.mapLong(e->{
                final var t = mapper.apply(e);
                if(t!=null && ar.get()==null)ar.set((Class<T>)t.getClass());
                return t;
            }).toArray(n->(T[])Array.newInstance(ar.get(), n));
        }

        /**
         * 使用mapper变换范围生成相应的   采样点序列 数据 列表 ,dblL的方法的别名
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型数据流
         */
        public <T> List<T> list(final Function<Double,T> mapper){
            
            return this.dblL(mapper);
        }

        /**
         * 生成一个对象Range,首位分别增加同等偏移数量offset
         * @param offset 偏移数量
         * @return 一个新生成的Range对象
         */
        public Range add(final Number offset) {
            
            return Range.of(this.start.doubleValue()+offset.doubleValue(), 
                this.end.doubleValue()+offset.doubleValue());
        }

        /**
         * 生成一个对象Range,首位分别增加同等偏移数量offset
         * @param offset 偏移数量
         * @return 一个新生成的Range对象
         */
        public Range sub(final Number offset) {
            
            return Range.of(this.start.doubleValue()-offset.doubleValue(), 
                this.end.doubleValue()-offset.doubleValue());
        }

        /**
         * 生成一个对象Range,首位分别乘以同等偏移数量scale
         * @param scale 偏移数量
         * @return 一个新生成的Range对象
         */
        public Range mul(final Number scale) {
            
            return Range.of(this.start.doubleValue()*scale.doubleValue(), 
                this.end.doubleValue()*scale.doubleValue());
        }

        /**
         * 生成一个对象Range,首位分别乘以同等偏移数量scale
         * @param scale 偏移数量
         * @return 一个新生成的Range对象
         */
        public Range div(final Number scale) {
            
            return Range.of(this.start.doubleValue()/scale.doubleValue(), 
                this.end.doubleValue()/scale.doubleValue());
        }
        
        /**
         * 反向应用的Map<br>
         * T 类型的流
         * 
         * @param <T> 元素类型
         * @param mappers 映射器 集合
         * @return T 类型数据流
         */
        @SafeVarargs
        final public <T> Stream<T> reverseMap(final Function<Range,T> ... mappers){
            
            return Arrays.stream(mappers).map(mapper->mapper.apply(this));
        }
        
        /**
         * 反向应用的FlatMap
         * 用  mapper 变换 生成一个  T 类型的   采样点序列 数据流 
         * @param <T> 元素类型
         * @param mappers 映射器集合
         * @return T 类型的   采样点序列 数据流 
         */
        @SafeVarargs
        final public <T> Stream<T> reverseFlatMap(final Function<Range,Stream<T>> ... mappers){
            
            return Arrays.stream(mappers).flatMap(mapper->mapper.apply(this));
        }
        
        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流 :mapDouble 的别名
         * @param <T> 元素类型
         * @param mapper 映射器: double->T
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> map(final Function<Double,T> mapper){
            
            return this.mapDouble(mapper);
        }
        
        /**
         * 区间范围 采样点的 数据变换。
         * @param <T> 返回结果的参数类型，mapper变换的结果类型。
         * @param mapper 二元映射函数 (i:索引号 从0开始,dbl:采样点)->t
         * @return T 类型的 采样点数据流 
         */
        public <T> Stream<T> map2(final BiFunction<Integer,Double,T> mapper) {
            
            final var ai = new AtomicInteger(0); // 计数器
            
            return this.dblStream().map(d->mapper.apply(ai.getAndIncrement(), d));
        }

        /**
         * 2维空间张成器
         * 
         * @param <T> 元素类型
         * @param mapper 维度数据变换器:double->t
         * @return 增加一个 新维度的 tt的数据流,维度比 tt的维度多一个,即2维度 数据流,流的长度为 [start,end)
         */
        @SuppressWarnings("unchecked")
        public <T> Function<T,Stream<T[]>> derived_2d_ctor(final Function<Double,T> mapper){
            
            return t -> this
                .mapDouble(mapper) // 映射成T类型的采样点流 
                .map( e -> { // t和e 合并成一个数组 向量 [t,e]
                    
                    final var ll = Arrays.asList(t,e);// 组合成tt列表
                    final var clazz = ll.stream()
                        .dropWhile(p->p==null).findFirst() // 选取非空元素的 类型作为采样点类型T的实际类型。
                        .map(p->(Class<T>)p.getClass())
                        .orElse((Class<T>)Object.class);// 提取元素类型类用于生成数组结构。
                    
                    return ll.toArray(n->(T[])Array.newInstance(clazz, n));
                });// map
        }
        
        /**
         * 2维空间张成器
         * 
         * @return double 类型的   二维数据流
         */
        public Function<Double,Stream<Double[]>> derived_2d_ctor(){
            
            return this.derived_2d_ctor(e->e);
        }

        /**
         * n维空间张成器
         * 
         * @param <T> 元素类型
         * @param mapper 维度数据变换器
         * @return 增加一个 新维度的 tt的数据流,维度比 tt的维度多一个，流的长度为 [start,end)
         */
        public <T> Function<T[],Stream<T[]>> derived_nd_ctor(final Function<Double,T> mapper){
            
            return tt->this.mapDouble(mapper).map(e->{
                final var aa = Arrays.copyOf(tt, tt.length+1);
                aa[aa.length-1]=e;
                return aa;
            });
        }
        
        /**
         * n维空间张成器
         * 
         * @return 增加一个 新维度的 tt的数据流,维度比 tt的维度多一个，流的长度为 [start,end)
         */
        public Function<Double[],Stream<Double[]>> derived_nd_ctor(){
            
            return this.derived_nd_ctor(e->e);
        }
        
        /**
         * 张成多维向量空间 <br>
         * 
         * 使用示例：<br>
         * final var rng = Range.of(2);// 0,1 <br>
         * rng.span(rng.derived_2d_ctor(),rng.derived_nd_ctor(),Range.of(3).derived_nd_ctor()) <br>
         *  .map(Arrays::asList)<br>
         *  .forEach(System.out::println); <br>
         * 
         * @param <T> 向量空间的元素类型
         * @param derived_2d_ctor 2维空间张成器
         * @param derived_nd_ctors n维空间张成器序列
         * @return 依次采用 d_2d_ctor, d_nd_ctors, 进行累计扩展的 n维度 空间。空间的维数为 2+d_nd_ctors。length
         */
        @SafeVarargs
        final public <T> Stream<T[]> span (
            final Function<Double,Stream<T[]>> derived_2d_ctor,
            final Function<T[],Stream<T[]>> ... derived_nd_ctors){
            
            final var identity = this.dblStream().flatMap(derived_2d_ctor); // 初次张成二维空间,然后再用reduce的办法进行空间的迭代累积扩增
            
            // 累加形成N维度空间
            return Arrays.stream(derived_nd_ctors).reduce(identity,(ss,f)->ss.flatMap(f), Stream::concat); 
        }

        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流 :flatMapDouble 的别名
         * @param <T> 元素类型
         * @param mapper 映射器:Double->[tt]
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> flatMap(final Function<Double,Stream<T>> mapper){
            
            return this.flatMapDouble(mapper);
        }
        
        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器:int->t
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> mapInt(final Function<Integer,T> mapper){
            
            return this.dblStream().map(e->e.intValue()).map(mapper);
        }
        
        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器:int->[tt]
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> flatMapInt(final Function<Integer,Stream<T>> mapper){
            
            return this.dblStream().map(e->e.intValue()).flatMap(mapper);
        }
        
        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器:long->t
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> mapLong(final Function<Long,T> mapper){
            
            return this.dblStream().map(e->e.longValue()).map(mapper);
        }
        
        /**
         * 用  mapper 变换 生成一个 T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器:long->[tt]
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> flatMapLong(final Function<Long,Stream<T>> mapper){
            
            return this.dblStream().map(e->e.longValue()).flatMap(mapper);
        }
        
        /**
         * T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> mapDouble(final Function<Double,T> mapper){
            
            return this.dblStream().map(e->e.doubleValue()).map(mapper);
        }
        
        /**
         * T 类型的   采样点序列 数据流
         * 
         * @param <T> 元素类型
         * @param mapper 映射器
         * @return T 类型的   采样点序列 数据流
         */
        public <T> Stream<T> flatMapDouble(final Function<Double,Stream<T>> mapper){
            
            return this.dblStream().map(e->e.doubleValue()).flatMap(mapper);
        }
        
        /**
         * 采样点遍历 <br>
         * 通cs遍历访问 Range范围中的每个 采样点。
         * @param cs 回调函数 dbl->{}
         * @return Range 对象本身已方便实现链式编程
         */
        public Range forEach(final Consumer<Double> cs) {
            
            this.dblStream().forEach(cs);
            
            return this;
        }
        
        /**
         * 带序号的 采样点遍历 <br>
         * 通cs遍历访问 Range范围中的每个 采样点。 <br>
         * 遍历的索引序号从0开始 <br>
         * <br>
         * @param cs 二元回调函数 (i:索引号,dbl:采样点)->{}
         * @return Range 对象本身已方便实现链式编程
         */
        public Range forEach(final BiConsumer<Integer,Double> cs) {
            
            final var ai = new AtomicInteger(0); // 计数器
            this.dblStream().forEach(d->cs.accept(ai.getAndIncrement(), d));
            
            return this;
        }
        
        /**
         * 使用collector将范围归集为目标对象 
         * @param <A> 积累器的类型accumulation
         * @param <R> 返回的结果
         * @param collector 归集器
         * @return R类型的对象
         */
        public <A,R> R collect(final Collector<Double,A,R> collector) {
            
            return this.dblStream().collect(collector);
        }
        
        /**
         * 构造出一个可以容纳有 n个采样点 区间范围
         * @param size 采样点的数量
         * @return 新的而区间对象
         */
        public Range limit(final Number size) {
            
            if(size.doubleValue()<1) {
                System.err.println("采样点数量size不能小于1,复制拷贝当前Range对象给予返回");
                return new Range(this);
            }
            
            final var step = size.doubleValue() == 1
                ? this.end()-this.start()
                : Math.abs( this.end()-this.start() ) / ( size.intValue() );// 计算步长,注意 这里不设置符号,仅仅取一个绝对值
            
            final var rng = new Range(this.start, this.end, step);
            final var aa = rng.toArray();
            if (aa.length > size.intValue()) {// 由于四舍五入而造成的 step太小了，所以这里 为 step 增加一个调节量
                final var eps = Math.abs(Math.abs(end()) - Math.abs(aa[aa.length - 1]));// 误差调节
                final var p = Math.abs(step) + eps;
                return new Range(this.start, this.end, p);
            } else {
                return rng;
            }
            
        }
        
        /**
         * 调节增长步调,以便生成非均匀序列点。
         * @param tri_nexter next 生成器
         * @return Range对象本身,以便实现链式编程。
         */
        public Range regulate(final TriFunction<Integer, Double ,Double, Double> tri_nexter){
            
           this.tri_nexter = tri_nexter;
           
           return this;
        }
        
        /**
         * Array Collector : 对一个 List<T> 进行归纳: ss 表示 mapper 是一个流Stream->U
         * @param <T> 归纳元素类型
         * @param <U> 返回结果类型
         * @param mapper 流变换函数  tt-> U 
         * @reutrn U 类型的对象
         */
        @SuppressWarnings("unchecked")
        public static <T,U> Collector<T,List<T>,U> aaclc(final Function<T[],U> mapper){
            return Collector.of(
                ()->new ArrayList<T>(),
                (aa,a)->aa.add(a),
                (aa,bb)->{aa.addAll(bb);return aa;},
                ll->mapper.apply(ll.toArray(n->{
                    final var componentType = ll.stream().filter(e->e!=null).findFirst()
                        .map(e->(Class<T>)e.getClass()).orElse((Class<T>)Object.class);
                    return (T[])Array.newInstance(componentType, n);
                }))
            );// Collector
        }
        
        /**
         * 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         * 
         * 比如:Range.cph(2,2) 生成也给如下的结构
         * [0, 0] <br>
         * [0, 1] <br>
         * [1, 0] <br>
         * [1, 1] <br>
         * 
         * @param dims 空间维度列表,大于0的整数序列。比如 2,2,2 生成一个 2x2x2的cube结构 
         * @return 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         */
        @SuppressWarnings("unchecked")
        public static Stream<int[]> cph(final Integer ... dims){
            
            if(dims==null || dims.length<1) return Stream.of();// dims 为空或 长度为0,返回一个空的流
                
            final var tup = TVec.split(dims, 2);// 分拆成 这样的结构: [[0,1],[2,3,...]]
            if(tup.size()>1) {// 分解成功,dims 长度 >=3
                final var bigheader = tup.get(0);// 前半段
                final var bigtail = tup.get(1);// 后半段
                final var derived_2d_ctor = new Range(bigheader[1]).derived_2d_ctor();// 二维增扩器
                final var derived_nd_ctors = Arrays.stream(bigtail).map(Range::new).map(Range::derived_nd_ctor)
                    .toArray(n->(Function<Double[],Stream<Double[]>>[])Array.newInstance(Function.class, n)); // n维度增扩器集合
                final var rng = new Range(bigheader[0]);// bigheader[0] 作为增长主轴。
                final var stream = rng.span(derived_2d_ctor, derived_nd_ctors);// 展开向量空间。
                
                return stream.map(NVec::of).map(NVec::ints);
            }else {// dims 长度 小于等于2，即 <3
                if(dims.length<2) // dims 的维度为 1
                    return Range.of(dims[0]).intS().mapToObj(e->new int[]{e});
                else  // dims长度为 2
                    return Range.of(dims[0]).span(Range.of(dims[1]).derived_2d_ctor())
                        .map(NVec::of).map(NVec::ints);
            }
        }
        
        /**
         * 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         * 
         * 比如:Range.cph(2,2) 生成也给如下的结构
         * [0, 0] <br>
         * [0, 1] <br>
         * [1, 0] <br>
         * [1, 1] <br>
         * 
         * @param dims 空间维度列表,大于0的整数序列。比如 2,2,2 生成一个 2x2x2的cube结构 
         * @return 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         */
        public static Stream<int[]> cph2(final int ... dims){
            
            return cph(Arrays.stream(dims).boxed().toArray(Integer[]::new));
        }

        /**
         * 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         * 
         * 比如:Range.cph(2,2) 生成也给如下的结构
         * [0, 0] <br>
         * [0, 1] <br>
         * [1, 0] <br>
         * [1, 1] <br>
         * 
         * @param dims 空间维度列表,NVec包装的对象,大于0的整数序列。比如 2,2,2 生成一个 2x2x2的cube结构 
         * @return 全排列 成一个  dims[0] x  dims[1] x ... x dims[n] 的数值空间
         */
        public static Stream<NVec> cph(NVec dims){
            
            return cph(dims.integers()).map(NVec::of);
        }
        
        /**
         * 构建采样空间<br>
         * 对一组rngs中的采样点做全排序，即定义空间多维空间采样点<br>
         * @param rngs 维度范围集合,采样点范围，维度分量(单元)范围 集合。
         * @return 多维空间采样点集合
         */
        public static Stream<NVec> cph( final Range ... rngs ) {
            
            final Double[][] aa = Arrays.stream(rngs).map(e->e.dblA2()).toArray(Double[][]::new);
            final var p = new Permutation<Double>(aa);
            List<Double[]> ll = new LinkedList<Double[]>();
            p.permute(e->ll.add(e.clone()));
            
            return ll.stream().map(NVec::of);
        }
        
        /**
         * 构建采样空间<br>
         * 对一组rngs中的采样点做全排序，即定义空间多维空间采样点
         * @param rngs 维度范围集合,采样点范围，维度分量(单元)范围 集合。
         * @param cs 结果回调函数,空间的采样点的  回调入口函数,point->{},
         * @return 多维空间采样点集合
         */
        public static void cphx( Consumer<NVec> cs,final Range ... rngs) {
            
            final Double[][] ranges = Arrays.stream(rngs).map(e->e.dblA2()).toArray(Double[][]::new);
            final var p = new Permutation<Double>(ranges);
            p.permute(NVec::of,cs);
        }

        /**
         * 构建采样空间<br>
         * 对一组rngs中的采样点做全排序，即定义空间多维空间采样点<br>
         * @param rngs 维度范围集合,采样点范围，维度分量(单元)范围 集合。
         * @param cs 结果回调函数,空间的采样点的  回调入口函数,dd->{},
         * @return 多维空间采样点集合
         */
        public static void cphx2( Consumer<Double[]> cs,final Range ... rngs) {
            
            final Double[][] ranges = Arrays.stream(rngs).map(e->e.dblA2()).toArray(Double[][]::new);
            final var p = new Permutation<Double>(ranges);
            p.permute(cs);
        }

        /**
         * 多维数据范围的空间采样点，构建器 <br>
         * 多维数据范围的 空间采样点的 原理就是 构造 每个 采样点范围在 各自维度的 全排列。<br>
         * 采样点范围 的 维度 用 在 空间采样点 拥有一个 唯一且 固定的 索引号。即 point[i]表示第i个维度的 采样点范围 即 与 range[i]相对应。<br>
         * 
         * @author gbench
         *
         * @param <T> 排序的元素类型
         */
        public static class Permutation<T>{
            
            /**
             * 构造以排序结构
             * 
             * ranges[i] 表示 排序结果的定义i个位置所选取的数据范围。                       
             * 比如 new Double[][]{ <br>                                 
             *  {1,2}, <br>                                            
             *  {3,4} <br>                                             
             * };<br>                                                  
             * 将生成一个 如下的 结果                                            
             * [1.0, 3.0] <br>                                             
             * [1.0, 4.0] <br>                                             
             * [2.0, 3.0] <br>                                             
             * [2.0, 4.0] <br>                                             
             * 
             * @param ranges 是一个 范围定义 结构. <br>
             * 
             */
            @SuppressWarnings("unchecked")
            public Permutation(final T[]... ranges) {
                
                final var componentType = ranges.getClass().getComponentType().getComponentType();
                this.point = (T[])Array.newInstance(componentType, ranges.length);
                this.ranges = ranges;
            }

            /**
             * 构造全排列
             * @param s 开始位置
             * @param action
             */
            public void permute(final int s,Consumer<T[]>action) {
                
                final var e = ranges.length; // 结束位置，师傅完成了最终的运算。
                if(s>=e)action.accept(point);
                else {
                    Arrays.asList(ranges[s]).forEach(i->{
                        point[s]=i;// 在s位置写入i元素
                        permute(s+1,action);// 然后移步到 下一个位置继续写。
                    });// forEach
                }//if
            }//
            
            /**
             * 构造全排列
             * 对 ranges进行全排序
             * @param action 回调函数
             */
            public void permute(final Consumer<T[]>action) {
                this.permute(0,action);
            }
            
            /**
             * 对 ranges进行全排序
             * @param mapper 的结果类型，
             * @param mapper 数组结构变换器,把 数组类型的tt,变换成一个action可以接受的U的数据类型。tt->u
             * @param action 回调函数
             */
            public <U> void permute(final Function<T[],U> mapper,final Consumer<U>action) {
                
                this.permute(0,e->action.accept(mapper.apply(e)));
            }
            
            /**
             * 构造排序组合对象。
             * @param <T>
             * @param ranges
             * @return
             */
            public static<T> Permutation<T> of(T[][] ranges){
                return new Permutation<>(ranges);
            }
            
            private T[] point;// 结果空间:空间采样点
            private T[][] ranges; // 排序列表
        }
        
        /**
         * 拷贝构造一个区间对象
         * 
         * @param range 被拷贝的区间对象
         */
        public static Range of (final Range range){
            
           return  new Range(range);
        }
        
        /**
         * 拷贝构造一个区间对象：使用静态采样点
         * 
         * @param points 静态，采样点序列
         */
        public static Range of(final List<? extends Number> points) {
            
            return new Range(points.stream().map(Number::doubleValue).collect(Collectors.toList()));
        }
        
        /**
         * 区间对象:[start,end) <br>
         * 标准 包含 位置 状态 配置说明: 1#start 标准-包含;2#end 标准-不包含 <br>
         * 标准包含状态: start包含,end不包含 <br>
         * start 开始数量 默认为 0 inclusive
         * @param end 截止数量  exclusive
         */
        public static Range of(final Number end) {
            return of(0,end);
        }
        
        /**
         * 区间对象:[start,end) <br>
         * 标准 包含 位置 状态 配置说明: 1#start 标准-包含;2#end 标准-不包含 <br>
         * 标准包含状态: start包含,end不包含 <br>
         * @param start 开始数量 inclusive
         * @param end 截止数量  exclusive
         */
        public static Range of(final Number start,final Number end) {
            
            final var step = (start.doubleValue()<=end.doubleValue()?1:-1);
            
            return of(start,end,step);
        }
        
        /**
         * 区间对象:[start,end) <br>
         * 标准 包含 位置 状态 配置说明: 1#start 标准-包含;2#end 标准-不包含 <br>
         * 标准包含状态: start包含,end不包含 <br>
         * @param start 开始数量 inclusive
         * @param end 截止数量  exclusive
         * @param step 步长
         */
        public static Range of(final Number start,final Number end,Number step) {
            
            return new Range(start,end,step);
        }
        
        /**
         * 区间对象(start,end) <br>
         * 非标准 包含 位置 状态 配置说明: 1#start 非标准-不包含;2#end 标准-不包含 <br>
         * 非标准包含状态: start不包含,end不包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量 exclusive
         * @param end 截止数量  exclusive
         * @param step_absolute 步长的绝对值
         * @return 一个新生成的Range对象
         */
        public static Range of1(final Number start,final Number end) {
            
            final var step = (start.doubleValue()<=end.doubleValue()?1:-1);
            
            return of1(start,end,step);
        }

        /**
         * 区间对象(start,end)<br>
         * 非标准 包含 位置 状态 配置说明: 1#start 非标准-不包含;2#end 标准-不包含
         * 非标准包含状态: start不包含,end不包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量 exclusive
         * @param end 截止数量  exclusive
         * @param step_absolute 步长的绝对值
         * @return 一个新生成的Range对象
         */
        public static Range of1(final Number start,final Number end,
            final Number step_absolute) {
            
            final var final_step = (start.doubleValue()<=end.doubleValue()?1:-1)
                * Math.abs(step_absolute.doubleValue());// 步长
            
            return new Range(start.doubleValue()+final_step,end,final_step);// 多增加一个步长以保证尾包含
        }

        /**
         * 区间对象[start,end]<br>
         * 非标准 包含 位置 状态 配置说明: 1#start 标准-包含;2#end 非标准-包含
         * 非标准包含状态: start包含,end包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量 inclusive
         * @param end 截止数量  inclusive
         * @return 一个新生成的Range对象
         */
        public static Range of2(final Number start,final Number end) {
            
            final var step = (start.doubleValue()<=end.doubleValue()?1:-1);
            
            return of2(start,end,step);
        }
        
        /**
         * 区间对象[start,end]<br>
         * 非标准 包含 位置 状态 配置说明: 1#start 标准-包含;2#end 非标准-包含 <br>
         * 非标准包含状态: start包含,end包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量 inclusive
         * @param end 截止数量  inclusive
         * @param step_absolute 步长的绝对值
         * @return 一个新生成的Range对象
         */
        public static Range of2(final Number start,final Number end,
            final Number step_absolute) {
            
            final var final_step = (start.doubleValue()<=end.doubleValue()?1:-1)
                * Math.abs(step_absolute.doubleValue());// 步长
            
            return new Range(start,end.doubleValue()+final_step,final_step);// 多增加一个步长以保证尾包含
        }
        
        /**
         * 区间对象(start,end]<br>
         * 非标准 包含 位置 状态 配置说明: 1#start 非标准-不包含; 2#end 非标准-包含<br>
         * 非标准包含状态: start 不包含,end 包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量  exclusive
         * @param end 截止数量  inclusive
         * @return 一个新生成的Range对象
         */
        public static Range of12(final Number start,final Number end) {
            
            final var step = (start.doubleValue()<=end.doubleValue()?1:-1);
            
            return of12(start,end,step);
        }
        
        /**
         * 区间对象(start,end]<br>
         * 非标准 包含 位置 状态 配置说明: 1#start 非标准-不包含;2#end 非标准-包含
         * 非标准包含状态: start 不包含,end 包含 <br>
         * 带有数字后缀的of表示对应位置上的元素与默认的of处处理方式即半闭半开[start,end)相反。<br>
         * 
         * @param start 开始数量  exclusive
         * @param end 截止数量  inclusive
         * @param step_absolute 步长的绝对值
         * @return 一个新生成的Range对象
         */
        public static Range of12(final Number start,final Number end,
            final Number step_absolute) {
            
            final var final_step = (start.doubleValue()<=end.doubleValue()?1:-1)
                * Math.abs(step_absolute.doubleValue());// 步长
            
            return new Range(start.doubleValue()+final_step,
                end.doubleValue()+final_step,final_step);// 多增加一个步长以保证尾包含
        }
        
        /**
         * 三元函数
         * @author gbench
         *
         * @param <T> 第一 参数
         * @param <U> 第二参数
         * @param <V> 第三参数
         * @param <R> 函数结果
         */
        @FunctionalInterface
        public static interface TriFunction<T,U,V,R>{
            
            /**
             * 三元函数的应用结果 (t,u,v)->r
             * @param t 第一 参数
             * @param u 第二参数
             * @param v 第三参数
             * @return 函数结果
             */
            public R apply(T t,U u,V v);
        }
        
        private Number start; // 开始位置
        private Number end; // 结束位置
        private Number step; // 步长
        
        private Supplier<Double> start_supplier = ()->start.doubleValue();// step变换器,index,last,step
        private TriFunction<Integer,Double,Double,Double> tri_nexter = (i,l,s) -> l+s;// step变换器,index,last,step
        private BiPredicate<Integer, Double> predicate_hasnext = (i,c) -> 
            start.doubleValue() < end.doubleValue() 
                ? end.intValue()==Double.MAX_VALUE ? true: c<end.doubleValue()
                : end.intValue()==Double.MAX_VALUE ? true: c>end.doubleValue();// step变换器,index,current
        private List<Double> points = null; // 枚举类型的数据
    }
    
    /**
     * T 类型的向量,即 长度为n的元组 <br> 
     * <br>
     * 向量用于表示一个 点概念:小则无内的意思，<br>
     * 即它的主要作用就是 通过累加(结构化)的方式 组合形成 其他的 更富有实际意义  的 实在 概念。<br>
     * 所以向量 是一个 (原材料概念), 素材概念, 是用于 构成更高级的概念的 概念 即 单元概念 或是 原子概念  <br>
     * 
     * @author gbench
     *
     * @param <T> 向量的元素的类型
     * @param <SELF> 本身类型：当前类的实际类型，这是一种泛型化实现的向前兼容的设计（技巧）
     */
    public static abstract class TVec<T,SELF> {
        
        /**
         * 构造函数
         * @param data 源数据
         */
        public TVec(final T[] data){
            this.data = data;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值<br>
         * vec.evaluate((i,v)->vec.set(i,v),1,23);<br>
         * @param callback 回调函数
         * @param oo (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        @SuppressWarnings("unchecked")
        public SELF evaluate(final BiConsumer<Integer,T> callback,
            final Object ... oo) {
            
            final var size = oo.length;
            for(var i=0;i<size-1;i+=2) callback.accept((Integer)oo[i],(T)oo[i+1]);
            
            return self();
        }
        
        /**
         * 返回当前对象本身。这是泛型，向前兼容的设计实现。
         * @return 返回当前对象本身 即 this
         */
        @SuppressWarnings("unchecked")
        public SELF self() {
            
            return (SELF)this;
        }
        
        /**
         * 返回第i个元素的值
         * @param i 索引编号 从0开始
         * @return T 获取第i元素的值
         */
        public T get(final int i) {
            
            if(i>=this.data.length||i<0) return null;
            
            return this.data[i];
        }
        
        /**
         * 设置第i个元素的值
         * 
         * @param i 设置的位置，从0开始
         * @param value 设置的值
         * @return 对象本身以实现链式编程
         */
        public SELF set(final int i,T value) {
            
            return this.set(i, e->value);
        }
        
        /**
         * 设置第i个元素的值
         * 
         * @param i 设置的位置，从0开始
         * @param value 设置的值
         * @return 对象本身以实现链式编程
         */
        public SELF set(final int i,Function<T,T> valueer) {
            
            this.data[i] = valueer.apply(this.get(i));
            
            return this.self();
        }
        
        /**
         * 对data进行按照索引位置进行拆分<br>
         * <br>
         * @param <U> 数组元素类型
         * @param positions 大于0的整数列表,表示切分的位点, 即切分索引位置<br>
         * 切分索引位置（区间结尾索引exclusive,所以需要的是大约0的整数） 序列,<br>
         * 对于超出过data.length则视为数组的最大长度,<br>
         * 剔除超过数组长度范围所分割的区间。<br>
         * - 比如： [0,1,2,3],按照 {2,5,6}进行切分,定义的区间为:<br>
         * [0,2),[2,5),[5,6),由于[2,5)区间跨越了 data的长度,<br>
         * 所以给他矫正为[2,3),[5,6) 区间给予剔除。<br>
         * 结果返回 [0,1],[2,3]。<br>
         * - 比如：[0,1,2,3],按照[ 2 ] 进行切分,定义了区间 [0,2),[2,4),<br>
         * 即 定义区间的时候，会自动 补填 0,和 数组常常作为分割点。<br>
         * 即对于一个长度为4的数组来说,切分简化序列 [2]相当于 [0,2,4]的 切分完整序列。
         * @return 分割片段
         */
        public List<T[]> split(final Integer ...positions){
            
            return split(data,positions);
        }
        
        /**
         * 构造一个派生类
         * @param mutator 派生类构建器
         * @return 派生类 SELF
         */
        public SELF duplicate(Function<TVec<T,SELF>,SELF> self_creator) {
            return self_creator.apply(this);
        }
        
        /**
         * 复制，克隆一个当前对象的实例
         * @return NVec 实例以便实现链式编程
         */
        public abstract SELF duplicate();
        
        /**
         * 使用mapper转换集合data数据，生成u类型的数据流
         * @param <U> 结果的元素类型
         * @param mapper 数据流映射函数,t->u
         * @return U类型的数据流
         */
        public <U> Stream<U> map(final Function<T,U> mapper){
            
            return Arrays.stream(data).map(mapper);
        }
        
        /**
         * 使用mapper转换集合data数据，生成u类型的数据流
         * @param <U> 结果的元素类型
         * @param mapper 数据流映射函数,t->uu
         * @return U类型的数据流
         */
        public <U> Stream<U> flatMap(final Function<T,Stream<U>> mapper){
            
            return Arrays.stream(data).flatMap(mapper);
        }
        
        /**
         * 提取首位元素
         * @return 首位元素
         */
        public T car() {
            return this.data[0];
        }
        
        /**
         * 提取 末位元素
         * @return 末位元素
         */
        public T last() {
            
            if(this.size()<1)return null;
            return this.data[this.size()-1];
        }
        
        /**
         * 提取去除了首位元素后的其余元素序列
         * @return 除了首位元素后的其余元素序列
         */
        public T[] cdr() {
            
            return Arrays.copyOfRange(this.data, 1, this.data.length);
        }
        
        /**
         * 提取 去除末位元素后的 其余元素序列
         * @return 去除末位元素后的 其余元素序列
         */
        public T[] initial() {
            
            return Arrays.copyOfRange(this.data, 0, this.data.length-1);
        }
        
        /**
         * 突变出一个新的对象U
         * @param <U> 新的对象型
         * @param mutator 突变方法
         * @return 新的对象U
         */
        public <U> U mutate(final Function<T[],U> mutator) {
            
            return mutator.apply(Arrays.copyOf(this.data, this.size()));
        }
        
        /**
         * 保持结构不变的内容升级
         * @param updator 升级算法 t->t
         * @return 新的对象U
         */
        @SuppressWarnings("unchecked")
        public SELF alter(final Function<T,T> updator) {
            
            final var tvec = this.duplicate();
            this.forEach((i,t)->{
                ((TVec<T,SELF>)tvec).set(i, updator.apply(t));
            }); 
            
            return tvec;
        }
        
        /**
         * 保持结构不变的内容升级
         * @param updator 升级算法(i,t)->t
         * @return 新的对象U
         */
        @SuppressWarnings("unchecked")
        public SELF alter(final BiFunction<Integer,T,T> updator) {
            
            final var tvec = this.duplicate();
            this.forEach((i,t)->{
                ((TVec<T,SELF>)tvec).set(i, updator.apply(i,t));
            }); 
            
            return tvec;
        }
        
        /**
         * 生成以元素顺序与当前元素属性相反的 向量。
         * 如 [1,2,3] -> [3,2,1]
         * @return 元素顺序与当前元素属性相反的 新的 向量
         */
        public SELF reverse() {
            
            final var dd = this.duplicate();// 复制一个对象
            @SuppressWarnings("unchecked")
            final var data = ((TVec<T,SELF>)dd).data;// 提取数据空间
            final var n = data.length;
            
            for(int i=0;i<(n)>>>2-1;i++) {
                T t = data[i];
                data[i]=data[n-i-1];
                data[n-i-1]=t;
            }// for
            
            return dd;
        }
        
        /**
         * 返回向量数据:直接返回实例数据 引用。
         * 
         * @return 向量数据
         */
        public T[] data() {
            
            return this.data;
        }
        
        /**
         * 返回向量数据:拷贝生成一个新的数组
         * @return 向量数据
         */
        public T[] toArray() {
            
            return Arrays.copyOf(data, data.length);
        }
        
        /**
         * 把向量转换成一个T类型的列表对象
         * @return T类型的列表对象
         */
        public List<T> list(){
            
            return Arrays.asList(this.data);
        }
        
        /**
         * 把向量转换成一个U类型的列表对象
         * @parameter mapper 元素变换器
         * @return U类型的列表对象
         */
        public <U> List<U> list(final Function<T,U> mapper){
            
            return Arrays.stream(this.data).map(mapper).collect(Collectors.toList());
        }
        
        /**
         * 把向量转换成一个T类型的数据流
         * @return T类型的数据流
         */
        public Stream<T> stream(){
            
            return Arrays.stream(this.data).map(e->e);
        }

        /**
         * 把向量转换成一个U类型的数据流
         * @parameter mapper 元素变换器
         * @return U类型的数据流
         */
        public <U> Stream<U> stream(final Function<T,U> mapper){
            
            return Arrays.stream(this.data).map(mapper);
        }
        
        /**
         * 向量长度
         * @return 向量长度
         */
        public int size() {
            
            return this.data.length;
        }
        
        /**
         * 返回向量数据
         * @param mapper 映射函数 [t]->u
         * @return U 类型的数据
         */
        public <U> U data(final Function<T[],U> mapper) {
            
            return mapper.apply(this.data);
        }
        
        /**
         * 获取基础元素类型
         * @return 基础元素类型
         */
        @SuppressWarnings("unchecked")
        public Class<T> getComponentType(){
            
            return (Class<T>)this.data.getClass().getComponentType();
        }
        
        /**
         * 创建一个多维数组空间
         * 
         * @param dims 维度序列
         * @return 多维数组
         */
        public Object newArray(final int... dims) {
            
            return Array.newInstance(this.getComponentType(), dims);
        }
        
        /**
         * 创建一个多维数组空间
         * 
         * @param dims 维度序列
         * @return 多维数组
         */
        public Object newArray(final NVec dims) {
            
            return Array.newInstance(this.getComponentType(), dims.ints());
        }
        
        /**
         * reshape 多维数组多维数组变换函数。 <br>
         * 一个 典型的使用例子如下:<br>
         * final var mx = NVec.of(Range.of(size*size).dblA2(e->e%(size+1)==0?1:0)).reshape(BlasMatrix::dmx,size, size); // 单位矩阵  <br>
         * System.out.println(mx);
         * @param <U> 返回的结果类型
         * @param dims 维度空间长度(大于0的整数)的序列值,第一维度,第二维度,...,第n维
         * @param mapper 多维数组变换函数，由于无法预测用户在实际使用时 输入的dims的长度,所以我们无法准确的给出<br>
         *  mapper参数的具体数据的维度即Object后边有几个[],所以 这里使用一个Object[]来代替（用一个代表一切 ),即至少要有一维的意思。
         * @return 2维度矩阵
         */
        public <U> U reshape(final Function<Object[],U> mapper, final Integer ... dims){
            
            return mapper.apply((Object[])this.reshape(dims));
        }

        /**
         * 改变向量(数组)形状:变成多维数组,或者说不只有一维的数组 <br>
         * 当dims的长度小于1的时候，我们将拷贝一个现有的data（向量数据）作为返回结果。<br>
         * 即：Arrays.copyOf(this.data, dims.length<1?this.size():dims[0]);
         * 核心函数<br>
         * 
         * 用法示例: <br>
         * final var tt = (Double[][][])NVec.of(1,2,3,4,5,6,7,8).reshape(2,2,2); <br>
         * 会产生结构: <br>
         * A    B
         * [1.0, 2.0]   [3.0, 4.0]  
         * [5.0, 6.0]   [7.0, 8.0]
         * 
         * @param dims 维度空间长度(大于0的整数)的序列值,第一维度,第二维度,...,第n维
         * @return 新的数组对象,重新结构后的对象结构
         */
        public Object reshape(final Integer... dims) {
            
            if(dims.length<=1) {
                return Arrays.copyOf(this.data, dims.length<1?this.size():dims[0]);
            }
            
            final var dimsData = NVec.of(dims);// 维度空间
            final var volumeData = dimsData.bigtail(); // 去除第一索引后剩余的其他维度
            
            for (int i = 0; i < volumeData.size() - 1; i++) 
                volumeData.set(i,NVec.of(dimsData.cuts_picker(i + 1).apply(1)) // 提取后半部分的乘积
                   .product());// 计算每个索引的 所包含的 容量空间
            
            final var volumes = NVec.of(volumeData);// 维度的空间大小
            final var oo = (Object[]) this.newArray(NVec.of(dims));// 创建一个多维数组
            final var empty = this.size()<=0;
            Range.cph(NVec.of(dims)).forEach(index -> {
                final var i = (int) (index.bighead().dot(volumes) + index.last()); // 小标索引
                TVec.write(oo, empty?null:this.data[i % this.size()], index.ints());
            });

            return oo;
        }
        
        /**
         * reshape 1维度的简化函数 <br>
         * 
         * @param a 第一维长度
         * @return 1维数组
         */
        @SuppressWarnings("unchecked")
        public T[] reshape1(final int a){
            
            return (T[])this.reshape(a);
        }
        
        /**
         * reshape 2维度的简化函数 <br>
         * 
         * @param a 第一维度的长度
         * @param b 第二维度的长度
         * @return 2维数组
         */
        @SuppressWarnings("unchecked")
        public T[][] reshape2(final int a,final int b){
            
            return (T[][])this.reshape(a,b);
        }
        
        /**
         * reshape 2维度的简化函数 <br>
         * 
         * @param a 第一维度的长度:矩阵的行数
         * @param b 第二维度的长度:矩阵的列数
         * @return 2维度矩阵
         */
        @SuppressWarnings("unchecked")
        public DataMatrix<T> reshape2mx(final int a,final int b){
            
            return DataMatrix.of((T[][])this.reshape(a,b),true);
        }

        /**
         * reshape 3维度的简化函数 <br>
         * 
         * @param a 第二维度的长度
         * @param b 第二维度的长度
         * @param c 第三维度的长度
         * @return 3维度数组
         */
        @SuppressWarnings("unchecked")
        public T[][][] reshape3(final int a, final int b, final int c){
            
            return (T[][][])this.reshape(a,b,c);
        }
        
        /**
         * reshape 4维度的简化函数 <br>
         * 
         * @param a 第一维度的长度
         * @param b 第二维度的长度
         * @param c 第三维度的长度
         * @param d 第四维度的长度
         * @return 4维数组
         */
        @SuppressWarnings("unchecked")
        public T[][][][] reshape4(final int a, final int b, final int c, final int d){
            
            return (T[][][][])this.reshape(a,b,c,d);
        }
        
        /**
         * reshape 5维度的简化函数 <br>
         * 
         * @param a 第一维度的长度
         * @param b 第二维度的长度
         * @param c 第三维度的长度
         * @param d 第四维度的长度
         * @param e 第四维度的长度
         * @return 5维数组
         */
        @SuppressWarnings("unchecked")
        public T[][][][][] reshape5(final int a, final int b, final int c, final int d,final int e){
            
            return (T[][][][][])this.reshape(a,b,c,d,e);
        }
        
        /**
         * reshape 6维度的简化函数 <br>
         * 
         * @param a 第一维度的长度
         * @param b 第二维度的长度
         * @param c 第三维度的长度
         * @param d 第四维度的长度
         * @param e 第四维度的长度
         * @param f 第四维度的长度
         * @return 6维数组
         */
        @SuppressWarnings("unchecked")
        public T[][][][][][] reshape6(final int a, final int b, final int c, final int d,final int e,final int f){
            
            return (T[][][][][][])this.reshape(a,b,c,d,e,f);
        }
        
        /**
         * 使用collector将向量归集成目标对象 
         * @param <A> 积累器的类型accumulation
         * @param <R> 返回的结果
         * @param collector 归集器
         * @return R类型的对象
         */
        public <A,R> R collect(final Collector<T,A,R> collector) {
            return this.stream().collect(collector);
        }
        
        /**
         * 对T中的元素进行分组
         * 
         * @param <K> 键类型
         * @param classifier 分类器
         * @return 分组结构
         */
        public <K> Map<K, List<T>> groupBy(final Function<? super T, K> classifier) {
            
            return this.groupBy(classifier,Collectors.toList());
        }
        
        /**
         * 对T中的元素进行分组
         * 
         * @param <K> 键类型
         * @param <D> 规约的元素类型
         * @param classifier 分类器
         * @return 分组结构
         */
        public <K,D> Map<K, D> groupBy(final Function<? super T, K> classifier,
                Collector<? super T, ?, D> downstream) {
            
            return this.stream().collect(Collectors.groupingBy(classifier,downstream));
        }
        
        /**
         * 采样点遍历 <br>
         * 通cs遍历访问 Range范围中的每个 采样点。
         * @param cs 回调函数 dbl->{}
         * @return  ELF对象  对象本身已方便实现链式编程
         */
        public SELF forEach(final Consumer<T> cs) {
            
            this.stream().forEach(cs);
            
            return this.self();
        }
        
        /**
         * 带序号的 采样点遍历 <br>
         * 通cs遍历访问 Range范围中的每个 采样点。 <br>
         * 遍历的索引序号从0开始 <br>
         * <br>
         * @param cs 二元回调函数 (i:索引号,dbl:采样点)->{}
         * @return SELF对象 对象本身已方便实现链式编程
         */
        public SELF forEach(final BiConsumer<Integer,T> cs) {
            
            final var ai = new AtomicInteger(0); // 计数器
            this.stream().forEach(d->cs.accept(ai.getAndIncrement(), d));
            
            return this.self();
        }
        
        /**
         * 转换成 列向量(矩阵 )
         * @return 数据矩阵 size x 1
         */
        public DataMatrix<T> matrix() {
            
            return this.matrix(e->e);
        }
        
        /**
         * 转换成 列向量(矩阵 )
         * @param <U> 目标结果的类型
         * @param mapper 矩阵变换函数   mx(size x1)->U
         * @return 数据矩阵 size x 1
         */
        public <U> U matrix(final Function<DataMatrix<T>,U> mapper) {
            
            return mapper.apply(DataMatrix.of(this.reshape2(this.size(),1),true));
        }
        
        /**
         * 多维数组的 数据读取
         * 
         * @param obj  多维数组对象
         * @param path 维度索引
         * @return path 所标注的数据。
         */
        public static Object read(final Object obj, final int... path) {
            
            if(obj == null ) return null;
            
            if(obj instanceof Object[]) {
                return read((Object[])obj,path);
            }else {
                System.err.println("不能为非数组对象做write操作");
                return null;
            }//if
        }
        
        /**
         * 多维数组的 数据读取
         * 
         * @param <T>  多维数组元素的类型
         * @param oo   多维数组对象
         * @param path 维度索引
         * @return path 所标注的数据。
         */
        @SuppressWarnings("unchecked")
        public static <T> T read(final T[] oo, final int... path) {

            T[] objects = oo; // 单层数组节点
            for (int i = 0; i < path.length - 1; i++) { // 逐层下潜的获取得到单层数组节点
                int j = path[i];
                if (objects[j] != null && objects[j].getClass().isArray()) {
                    objects = (T[]) objects[j];
                } else {
                    return null;
                } // if
            }// for

            final int j = path[path.length - 1]; // 提取最后一层数据索引
            
            return j < objects.length ? objects[j] : null;
        }
        
        /**
         * 多维数组的 数据写入 把值指定的值 value <br>
         * 设置到 oo中 采用 多级索引序列 path 所指定的位置<br>
         * 
         * @param obj   待进行多维 索引路径访问的 对象，非多维数组不予写入
         * @param value 多维数组结构
         * @param path  多级索引序列的路径
         */
        public static void write(final Object obj, Object value, final int... path) {
            
            if(obj instanceof Object[]) {
                write((Object[])obj,value,path);
            }else {
                System.err.println("不能为非数组对象做write操作");
            }//if
        }
        
        /**
         * 多维数组的 数据写入 <br>
         * 把值指定的值 value 设置到 oo中 采用 多级索引序列 path 所指定的位置<br>
         * 
         * @param <T>   多维数组元素的类型
         * @param oo    多维数组结构，非多维数组不予写入
         * @param value 多维数组结构
         * @param path  多级索引序列的路径
         */
        public static <T> void write(final T[] oo, final T value, final int... path) {
            
            final var writer = distributor(oo, value); // 值分发器(写入器)
            
            writer.accept(path); // 把 value 分发到 indexes 
        }

        /**
         * 多维数组的 值分发器(把一个值投递到,或是写入某个位置上)
         * 
         * @param <T> 多维数组元素的类型
         * @param oo    多维数组
         * @param value 设置的值
         * @return 维度索引设置器  path->{}
         */
        @SuppressWarnings("unchecked")
        public static <T> Consumer<int[]> distributor(final T[] oo, final T value) {
            
            return path -> {
                
                T[] objects = oo; // 单层数组节点。
                for (int i = 0; i < path.length - 1; i++) { // 逐层下潜的获取得到单层数组节点
                    int j = path[i];
                    if (objects[j] != null && objects[j].getClass().isArray()) { // 对于数组类型进行深度遍历。
                        objects = (T[]) objects[j];
                    } else {
                        System.err.println("索引下潜时遇到空值或是非数组类型对象,无法触及到单层数组节点");
                        return;
                    } // if
                } // for

                final int j = path[path.length - 1]; // 提取 单层数组节点种的数据值
                
                if( j>=objects.length ) {// 索引坐标大于数组长度
                    final var p = Arrays.stream(path)
                        .mapToObj(e->e+"").collect(Collectors.joining(","));
                    System.err.println("in ["+p+"], 下标索引超过"+j+"数组长度空间范围 :"+objects.length+",不予设置");
                    return;
                }// if
                
                if (objects[j] instanceof Object[]) {// 为高纬进行赋值
                    if (value == null || value.getClass().isArray()) { // 高维数组的值只能是数组
                        objects[j] = value; // 数组类型的值的赋值
                    } else {
                        System.err.println(Arrays.stream(path)
                            .mapToObj(e->e+"").collect(Collectors.joining(","))+
                                " 所标定的元素是一个数组,赋值元素必须为数组类型");
                    }// if
                } else {
                    objects[j] = value;
                }// if
                
            }; // lambda 表达式 : path -> 
        }

        /**
         * 多维数组的指定维度的 数据修改器 (path位置上写入某个值)
         * 
         * @param <T>   多维数组元素的类型
         * @param oo    多维数组
         * @param value 设置的值
         * @param path  多级索引序列
         * @return 维度索引设置器  value->{}
         */
        @SuppressWarnings("unchecked")
        public static <T> Consumer<T> modifier(final T[] oo, final int... path) {
            
            return value -> {
                
                T[] objects = oo; // 单层数组节点。
                for (int i = 0; i < path.length - 1; i++) { // 逐层下潜的获取得到单层数组节点
                    int j = path[i];
                    if (objects[j] != null && objects[j].getClass().isArray()) {
                        objects = (T[]) objects[j];
                    } else {
                        System.err.println("索引下潜时遇到空值或是非数组类型对象,无法触及到单层数组节点");
                        return;
                    } // if
                } // for

                final int j = path[path.length - 1]; // 提取 单层数组节点种的数据值
                
                if( j>=objects.length ) {// 索引坐标大于数组长度
                    final var p = Arrays.stream(path)
                        .mapToObj(e->e+"").collect(Collectors.joining(","));
                    System.err.println("in ["+p+"], 下标索引超过"+j+"数组长度空间范围 :"+objects.length+",不予设置");
                    return;
                }// if
                
                if (objects[j] instanceof Object[]) {// 为高纬进行赋值
                    if (value == null || value.getClass().isArray()) { // 高维数组的值只能是数组
                        objects[j] = value; // 数组类型的值的赋值
                    } else {
                        System.err.println(Arrays.stream(path)
                            .mapToObj(e->e+"").collect(Collectors.joining(","))+
                                " 所标定的元素是一个数组,赋值元素必须为数组类型");
                    }// if
                } else {
                    objects[j] = value;
                }// if
                
            }; // lambda 表达式 : value -> 
        }
        
        /**
         * 对data进行按照索引位置进行拆分<br>
         * <br>
         * 
         * @param <U>       数组元素类型
         * @param data      待分割的元数据
         * @param positions 大于0的整数列表,表示切分的位点, 即切分索引位置<br>
         *                  切分索引位置（区间结尾索引exclusive,所以需要的是大约0的整数） 序列,<br>
         *                  对于超出过data.length则视为数组的最大长度,<br>
         *                  剔除超过数组长度范围所分割的区间。<br>
         *                  - 比如： [0,1,2,3],按照 {2,5,6}进行切分,定义的区间为:<br>
         *                  [0,2),[2,5),[5,6),由于[2,5)区间跨越了 data的长度,<br>
         *                  所以给他矫正为[2,3),[5,6) 区间给予剔除。<br>
         *                  结果返回 [0,1],[2,3]。<br>
         *                  - 比如：[0,1,2,3],按照[ 2 ] 进行切分,定义了区间 [0,2),[2,4),<br>
         *                  即 定义区间的时候，会自动 补填 0,和 数组常常作为分割点。<br>
         *                  即对于一个长度为4的数组来说,切分简化序列 [2]相当于 [0,2,4]的 切分完整序列。
         * @return 分割片段
         */
        public static <U> List<U[]> split(final U[] data, final Integer... positions){
            
            final var segments = new LinkedList<U[]>();// 分解片段
            final var pp = Stream.of(positions).sorted().collect(Collector.of(
                () -> new LinkedList<Integer>(), 
                (aa, a) -> aa.add(a),
                (aa, bb) -> {aa.addAll(bb);return aa;}));// 分割点
            if(pp.size()<1) { // 当切分位点小于1时候，默认不予切分 直接放回 原数据
                segments.add(data);
            }else {
                int start = 0;// 非法切分位点(exclusive),有效切分位点必须 >0
                if(pp.get(0)==0)pp.removeFirst();
                if(pp.getLast()<data.length)pp.addLast(data.length);// 补充为节点
                for(var p:pp){
                    final var flag = p>data.length;
                    segments.add(Arrays.copyOfRange(data,start,flag?data.length:p));// 复制
                    if(flag)break;
                    start = p;
                }//for
            }// if
            
            return segments;
        }
        
        /**
         * 生成数据矩阵
         * 
         * @param <T>     矩阵的元素类型
         * @param <SELF>  派生类类型
         * @param <U>     TVec的的具体元素类型,
         * @param columns TVec的后裔类型的元素构成的 列表
         * @return DataMatrix &lgt; T &gt; 维度为 size|5 x n
         */
        public static <T, SELF, U extends TVec<T, SELF>> DataMatrix<T> matrix_columns(final Stream<U> columns){
            
            return DataMatrix.of3(columns.map(TVec::data));// 把TVec视为列向量来 构造矩阵 
        }
        
        /**
         * 生成数据矩阵
         * 
         * @param <T> 矩阵的元素类型
         * @param <SELF> 派生类类型
         * @param <U> TVec的的具体元素类型,
         * @param rows TVec的后裔类型的元素构成的 列表
         * @return DataMatrix &lgt; T &gt; 维度为  size|5 x n
         */
        public static <T,SELF,U extends TVec<T,SELF>> DataMatrix<T> matrix_rows(final Stream<U> rows){
            
            return DataMatrix.of_rows(rows.map(TVec::data));// 把TVec视为列向量来 构造矩阵 
        }

        /**
         * data 向量的数据元素序列
         */
        protected final T[] data;
    }// TVec
    
    /**
     * 
     * XVec 元素为某种类型(X)的 向量,即 长度为n的元组<br>
     * <br>
     * @author gbench
     *
     * @param <T> 元素类型
     */
    public static class XVec<T> extends TVec<T, XVec<T>> {

        /**
         * 狗啊走函数
         * 
         * @param data 基础数据,T类型的数组，
         */
        public XVec(final T[] data) {
            
            super(data);
        }

        /**
         * 拷贝构造
         * 
         * @param tvec T类型的 基础向量
         */
        public XVec(final TVec<T, XVec<T>> tvec) {
            
            super(tvec.data);
        }

        /**
         * 衍生化出一个 同构对象:向量(数组)级别的变换
         * 
         * @param <U> 目标类型的类型
         * @param mapper 转换到目标类型类的的  映射 方法 : [t]->[u]
         * @return 内部元素类型为U类型的 的 XVec 
         */
        public <U> XVec<U> derive(final Function<T[], U[]> mapper) {
            
            return XVec.of(mapper.apply(this.data));
        }

        /**
         * 衍生化出一个 同构对象:元素级别变换
         * 
         * @param <U> mapper的结果 元素类型
         * @param mapper 元素变换器 t->u
         * @return 以U为元素类型的 XVec 
         */
        @SuppressWarnings("unchecked")
        public <U> XVec<U> derive2(final Function<T, U> mapper) {
            
            final var n = this.data.length;
            U[] aa = null;
            for (int i = 0; i < this.data.length; i++) {
                final var u = mapper.apply(this.data[i]);
                if (aa == null) aa = (U[]) Array.newInstance(u.getClass(), n);
                aa[i] = u;
            }//for
            
            return XVec.of(aa);
        }

        /**
         * 强制类型转换,如果完成 不同类型的之间的变换,请使用 derive2
         * 
         * @param <U> 目标类型类的类型
         * @param clazz 目标类型类
         * @return 变换了内部数据类型的 XVec 
         */
        @SuppressWarnings("unchecked")
        public <U> XVec<U> corece(final Class<U> clazz) {

            final var n = this.data.length;
            final U[] aa = (U[]) Array.newInstance(clazz, n);
            for (int i = 0; i < this.data.length; i++)
                aa[i] = (U) (this.data[i]);

            return XVec.of(aa);
        }

        /**
         * 构造一个克隆体
         */
        @Override
        public XVec<T> duplicate() {
            
            return this.duplicate(XVec::new);
        }
        
        /**
         * 提取大尾巴向量(除了1个小脑袋,其余全都是尾巴)
         * 
         * @return 除掉第一个元素的其他元素
         */
        public XVec<T> bigtail() {
            
            return this.tail(this.size()-1);
        }

        /**
         * 提取首部向量
         * @param n,尾部元素的数量,当 n大于数组长度时,返回全体元素
         * @return 除掉最后一个元素的其他元素
         */
        public XVec<T> tail(int n) {
            
            if (this.size() >= n) {
                return new XVec<>(Arrays.copyOfRange(this.data, this.size()-n,this.size()));
            } else {
                return new XVec<>(this.toArray());
            }
        }

        /**
         * 提取大脑袋向量提取大尾巴向量(除了1个小尾巴,其余全都是大脑袋)
         * 
         * @return 除掉最后一个元素的其他元素
         */
        public XVec<T> bighead() {
            
            return this.head(this.size()-1);
        }
       
       /**
        * 提取首部向量
        * @param n 头前的元素数量,当 n大于数组长度时,返回全体元素
        * @return 除掉最后一个元素的其他元素 
        */
       public XVec<T> head(final int n) {
           
           if(this.size()>=n) {
               return new XVec<>(Arrays.copyOf(this.data, n));
           }else {
               return new XVec<>(this.toArray());
           }
       }
        
        /**
         * 字符串格式化
         * 
         * @param formatter 元素格式化器
         * @return 格式化文本
         */
        public String toString(final Function<T, String> formatter) {
            final var line = Arrays.stream(this.data).map(formatter).collect(Collectors.joining(" , "));
            return "[ "+line+" ]";
        }
        
        /**
         * 字符串格式化
         * 
         * @return 格式化文本
         */
        @Override
        public String toString() {
            
            return this.toString(e->e+"");
        }

        /**
         * 构造一个向量对象
         * 
         * @param <T> 向量元素类型
         * @param tt  向量元素数组
         * @return XVec
         */
        @SafeVarargs
        public static <T> XVec<T> of(final T... tt) {
            
            return new XVec<>(tt);
        }
        
        /**
         * 把一个对象展开成单层元素
         * @param obj 被展开的数据对象
         * @return XVec的展开元素对象
         */
        public static XVec<Object> flat(final Object obj){
            
            return XVec.flat(obj,(i,e)->e);
        }
        
        /**
         * 把一个对象展开成单层元素
         * @param <T> 结果向量的元素类型
         * @param obj 被展开的数据对象
         * @param tclazz 类型标记,用于向编译器提供T的类型。使用强制转换的方式给予进行obj->T类型的变换
         * @return XVec的展开元素对象
         */
        @SuppressWarnings("unchecked")
        public static <T> XVec<T> flat(final Object obj, final Class<T>tclazz){
            
            return flat(obj,(idx,e)->(T)e);
        }
        
        /**
         * 把一个对象展开成单层元素
         * @param <T> 结果向量的元素类型
         * @param obj 被展开的数据对象
         * @param mapper 结果类型的变换器 (index, Object)->T
         * @return XVec的展开元素对象
         */
        public static <T> XVec<T> flat(final Object obj, final BiFunction<List<Integer>,Object,T> mapper){
            
            final var path = new LinkedList<Integer>();// 路径索引
            
            return flat(obj,mapper,path);
        }

        /**
         * 把一个对象展开成单层元素
         * @param <T> 结果向量的元素类型
         * @param obj 被展开的数据对象
         * @param mapper 结果类型的变换器:索引路径键值对 (path, Object)->T
         * @param path 路径索引
         * @return XVec的展开元素对象
         */
        @SuppressWarnings("unchecked")
        public static <T> XVec<T> flat(final Object obj, final BiFunction<List<Integer>,Object,T> mapper,
            final LinkedList<Integer> path){
            
            final var ll = new LinkedList<T>();// 结果列表
            final BiFunction<List<Integer>, Object, T> accessor = mapper == null ? (p, o) -> (T) o : mapper; // 数据访问器
            
            final Consumer<Object[]> dfs = oo -> { // deep first search
                for (int i = 0; i < oo.length; i++) {
                    path.add(i); // 在路径种加入第i项的元素索引
                    ll.addAll(XVec.flat(oo[i], accessor,path).list());
                    path.removeLast(); // 遍历完第i项之后,给予移除
                } //for
            };
            
            if(obj instanceof Object[]) {// 对数组类型的数据进行深度遍历
                dfs.accept((Object[])obj);
            }else {// 非数组元素保持输出到结果列表之中
                ll.add(accessor.apply(path,obj));
            } // if
            
            final var componentType = ll.stream().filter(e->e!=null).findFirst()
                .map(e->(Class<T>)e.getClass()).orElse((Class<T>)Object.class);// 元组鞍的的类型
            
            return XVec.of(ll.toArray(n->(T[])Array.newInstance(componentType, n)));
        }

        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @return IndexValuePair 扁平化的数据
         */
        public static List<IndexValuePair<Object>> flatten(final Object obj){
            
            return flatten(obj,e->e);
        }
        
        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param <T> IndexValuePair 的元素类型
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @param tclazz 类型标记,用于向编译器提供T的类型。使用强制转换的方式给予进行obj->T类型的变换
         * @return IndexValuePair 扁平化的数据
         */
        @SuppressWarnings("unchecked")
        public static <T> List<IndexValuePair<T>> flatten(final Object obj, final Class<T> tclazz){
            
            return flatten(obj,o->(T)o);
        }
        
        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param <T> IndexValuePair 的元素类型
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @return IndexValuePair 扁平化的数据
         */
        public static <T> List<IndexValuePair<T>> flatten(final Object obj, final Function<Object,T> mapper){
            
            final List<IndexValuePair<T>> ivps = new LinkedList<>(); // 返回结果
            
            XVec.flat(obj,(path,o) -> {// 路径缩影
                final var ivp = new IndexValuePair<>(path.stream()
                    .mapToInt(e->e).toArray(),mapper.apply(o));
                ivps.add(ivp);
                return ivp;
            });
            
            return ivps; // 返回结果
        }
        
        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @return IndexValuePair 扁平化的数据
         */
        public static Stream<IndexValuePair<Object>> flattenS(final Object obj){
            
            return flattenS(obj,o->o);
        }

        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param <T> IndexValuePair 的元素类型
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @param tclazz 类型标记,用于向编译器提供T的类型。使用强制转换的方式给予进行obj->T类型的变换
         * @return IndexValuePair 扁平化的数据
         */
        @SuppressWarnings("unchecked")
        public static <T> Stream<IndexValuePair<T>> flattenS(final Object obj, final Class<T> tclazz){
            
            return flattenS(obj,o->(T)o);
        }

        /**
         * 扁平化一个对象使之成为一个IVP列表
         * @param <T> IndexValuePair 的元素类型
         * @param obj 待扁平化的数据，一般为一个多维数组。
         * @return IndexValuePair 扁平化的数据
         */
        public static <T> Stream<IndexValuePair<T>> flattenS(final Object obj, final Function<Object,T> mapper){
            
            return flatten(obj,mapper).stream();
        }
        
    }// XVec
    
    /**
     * 数值向量(Number Vector) 即 长度为n的数字元组<br>
     * <br>
     * 一个数值向量用于表示一个 点概念:小则无内的意思，<br>
     * 即它的主要作用就是 通过累加(结构化)的方式 组合形成 其他的 更富有实际意义  的 实在 概念。<br>
     * 所以向量 是一个 (原材料概念), 素材概念, 是用于 构成更高级的概念的 概念 即 单元概念 或是 原子概念  <br>
     * 
     * @author gbench
     */
    public static class NVec extends XVec<Double> {
        
        /**
         * 数值类型的向量
         * @param vv 向量的数据元素序列
         */
        public NVec(final int[] vv){
            
            super(Arrays.stream(vv).mapToObj(Double::valueOf).toArray(Double[]::new));
        }
        
        /**
         * 数值类型的向量
         * @param vv 向量的数据元素序列
         */
        public NVec(final double[] vv){
            
            super(Arrays.stream(vv).boxed().toArray(Double[]::new));
        }
        
        /**
         * 数值类型的向量
         * @param vv 向量的数据元素序列,vv 数据 直接饮用。
         */
        public NVec(final Double[] vv){
            
            super(vv);
        }
        
        /**
         * 数值类型的向量
         * @param vv 向量的数据元素序列,vv 数据 拷贝引用
         */
        public NVec(final Number[] vv){
            
            super(Arrays.stream(vv).map(e->e==null?null:e.doubleValue()).toArray(Double[]::new));
        }
        
        /**
         * 数值类型的向量
         * @param rng 区间范围对象
         */
        public NVec(final Range rng){
            
            this(rng.dblA());
        }
        
        /**
         * 构造一个克隆体
         */
        public NVec duplicate() {

            return NVec.of(this);
        }
        
        /**
         * 保持结构不变的内容升级
         * @param updator double->double 元素修改算法
         * @return 新的对象NVec
         */
        public NVec alter(final Function<Double,Double> updator) {
            
            return NVec.of(super.alter(updator).data);
        }
        
        /**
         * 保持结构不变的内容升级
         * @param updator (integer,double)->double 元素修改算法
         * @return 新的对象NVec
         */
        public NVec alter(final BiFunction<Integer,Double,Double> updator) {
            
            return NVec.of(super.alter(updator).data);
        }
        
        /**
         * 生成以元素顺序与当前元素属性相反的 向量。
         * 如 [1,2,3] -> [3,2,1]
         * @return 元素顺序与当前元素属性相反的 向量
         */
        public NVec reverse() {
            return NVec.of(super.reverse().data);
        }
        
        /**
         * 设置第i个元素的值
         * 
         * @param i 设置的位置，从0开始
         * @param value 设置的值
         * @return 对象本身以实现链式编程
         */
        public NVec set(final int i,Double value) {
            
            return NVec.of(this.set(i, e->value).data);
        }

        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_set(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()]=idx2values[i+1].doubleValue();
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_add(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()] += idx2values[i+1].doubleValue();
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_sub(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()] -= idx2values[i+1].doubleValue();
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值(被减去)
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_sub2(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) 
                data[idx2values[i].intValue()] = idx2values[i+1].doubleValue()-data[idx2values[i].intValue()];
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_mul(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()] *= idx2values[i+1].doubleValue();
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_div(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()] /= idx2values[i+1].doubleValue();
            
            return this;
        }
        
        /**
         * 根据指定的索引位置，修改向量中对象位置的成分值(被出除去)
         * @param idx2values (索引,值) 的 序列 :索引1,值1,索引2,值2,...
         * @return NVec 自身以便实现链式编程
         */
        public NVec idval_div2(final Number ... idx2values) {
            
            final var size = idx2values.length;
            for(var i=0;i<size-1;i+=2) data[idx2values[i].intValue()] = 
                idx2values[i+1].doubleValue()/data[idx2values[i].intValue()];
            
            return this;
        }
        
        /**
         * 点积 运算 <br> 
         * 
         * 采用 循环 补位的方法,按照(this,nvec)的最大长度, 计算两个向量的 点积
         * @param nvec 另一个Nvec向量
         * @return 点集合运算的结果。
         */
        public Double dot(NVec nvec) {
            
            if(nvec.size()<1||this.size()<1)return null;
            
            return Stream.iterate(0d, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .reduce(0d,(a,i)->a+this.get(i.intValue()%this.size())*nvec.get(i.intValue()%nvec.size()));
        }
        
        /**
         * 向量间加法<br>
         * <br>
         * 把两个向量的同位置元素进行相加,并把和的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 和结果NVec
         */
        public NVec add(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())+nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量间减法<br>
         * <br>
         * this-nvec <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 差结果NVec
         */
        public NVec sub(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())-nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量间减法<br>
         * <br>
         * nvec-this <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 差结果NVec
         */
        public NVec sub2(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->nvec.dbl(i%nvec.size())-this.dbl(i%this.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量间乘法<br>
         * <br>
         * 把两个向量的同位置元素进行相乘,并把积的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 积结果NVec
         */
        public NVec mul(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())*nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量间除法<br>
         * <br>
         * this/nvec <br>
         * 把两个向量的同位置元素进行除法,并把商的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 商结果NVec
         */
        public NVec div(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())/nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量间除法<br>
         * <br>
         * nvec/this <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param nvec 另一个向量
         * @return NVec 商结果NVec
         */
        public NVec div2(NVec nvec) {
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->nvec.dbl(i%nvec.size())/this.dbl(i%this.size())).toArray(Double[]::new));
        }
        
        
        /**
         * 向量常数间减法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * 把两个向量的同位置元素进行相加,并把和的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 和结果NVec
         */
        public NVec add(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())+nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量常数间减法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * this-nvec <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 差结果NVec
         */
        public NVec sub(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->this.dbl(i%this.size())-nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量常数间减法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * nvec-this <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 差结果NVec
         */
        public NVec sub2(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->nvec.dbl(i%nvec.size())-this.dbl(i%this.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量常数间乘法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * 把两个向量的同位置元素进行相乘,并把积的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 积结果NVec
         */
        public NVec mul(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
            .map(i->this.dbl(i%this.size())*nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量常数间除法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * this/nvec <br>
         * 把两个向量的同位置元素进行除法,并把商的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 商结果NVec
         */
        public NVec div(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
            .map(i->this.dbl(i%this.size())/nvec.dbl(i%nvec.size())).toArray(Double[]::new));
        }
        
        /**
         * 向量常数间除法<br>
         * <br>
         * 把一个常数a 转换成 一个 长度为1的向量,即 NVec.of(a) ,然后 开展向量运算 <br> 
         * 
         * nvec/this <br>
         * 把两个向量的同位置元素进行减法,并把差的结果序列组合成向量NVec <br>
         * 计算过程采用 循环补位的方式 ,按照 this 和  nvec 的最大长度进行计算。 <br>
         * @param a 常数
         * @return NVec 商结果NVec
         */
        public NVec div2(final Number a) {
            
            final var nvec = NVec.of(a);
            
            return NVec.of(Stream.iterate(0, i->i+1).limit(Math.max(this.size(),nvec.size()))
                .map(i->nvec.dbl(i%nvec.size())/this.dbl(i%this.size())).toArray(Double[]::new));
        }
        
        /**
         * 连乘
         * @return 连乘 结果
         */
        public Double product() {
            
            return Arrays.stream(this.data()).reduce(1d, (aa,a)->aa*a);
        }
        
        /**
         * 连加
         * @return 连加结果
         */
        public Double sum() {
            
            return Arrays.stream(this.data()).reduce(0d, (aa,a)->aa+a);
        }
        
        /**
         * 统计信息(Double 类型)
         * @return 统计信息
         */
        public DoubleSummaryStatistics stats() {
            
            return Arrays.stream(this.data()).collect(Collectors.summarizingDouble(e->e));
        }
        
        /**
         * 平均数
         * @return 平均数
         */
        public Double mean() {
            
            return this.stats().getAverage();
        }
        
        /**
         * 最大值
         * @return 最大值
         */
        public Double max() {
            
            return this.stats().getMax();
        }
        
        /**
         * 最小值
         * @return 最小值
         */
        public Double min() {
            
            return this.stats().getMin();
        }
        
        /**
         * 方差: 注意 总体方差 是[除以n],不是样本方差[除以(n-1)]
         * @return 方差
         */
        public Double var() {
            
            return this.var(this);
        }
        
        /**
         * 方差: 注意 总体方差 是[除以n],不是样本方差[除以(n-1)]
         * @param nvec 另一个向量
         * @return 方差
         */
        public Double var(final NVec vec) {
            
            final var exy = this.dot(vec)/(this.size());
            final var exey = this.mean()*vec.mean();
            
            return exy-exey;
        }
        
        /**
         * 标准差:  注意 总体方差 是[除以n],不是样本方差[除以(n-1)]
         * @return 标准差
         */
        public Double sd() {
            
            return this.sd(this);
        }
        
        /**
         * 协方差的标准差 : 注意 总体方差 是[除以n],不是样本方差[除以(n-1)]
         * @param nvec 另一个向量
         * @return 标准差
         */
        public Double sd(NVec nvec) {
            
            return Math.sqrt(this.var(nvec));
        }
        
        /**
         * 仿射变换<br>
         * 平移
         * @param offset 偏移大小
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_offset(final Number offset) {
            
            return this.idval_add(0,offset,1,offset);
        }

        /**
         * 仿射变换<br>
         * 平移
         * @param offsetx x方向偏移大小
         * @param offsety x方向偏移大小
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_offset(final Number offsetx, final Number offsety) {
            
            return this.idval_add(0,offsetx,1,offsety);
        }
        
        /**
         * 仿射变换<br>
         * 缩放一下
         * @param scale 维度 缩放大小
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_scale(final Number scale) {
            
            return this.idval_mul(0,scale,1,scale);
        }
        
        /**
         * 仿射变换<br>
         * 缩放一下
         * @param scalex x 第一维度 缩放大小
         * @param scalex y 第二维度 缩放大小
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_scale(final Number scalex, final Number scaley) {
            
            return this.idval_mul(0,scalex,1,scaley.doubleValue());
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移:affine_scale_offset 的别名
         * @param scale 缩放比例
         * @param offset x,y 方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_scale_offset(final Number scale, final Number offset) {
            
            return this.affine_scale(scale).affine_offset(offset);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移:affine_scale_offset 的别名
         * @param scale 缩放比例
         * @param offsetx x方向平移量
         * @param offsety y方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_scale_offset(final Number scale, final Number offsetx, final Number offsety) {
            
            return this.affine_scale(scale).affine_offset(offsetx,offsety);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移
         * @param scalex x方向缩放比例
         * @param scaley y方向缩放比例
         * @param offsetx x方向平移量
         * @param offsety y方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine_scale_offset(final Number scalex, final Number scaley, 
            final Number offsetx, final Number offsety) {
            
            return this.affine_scale(scalex,scaley).affine_offset(offsetx,offsety);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移
         * @param scale x,y 方向的 缩放比例
         * @param offset x,y 方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine(final Number scale, final Number offset) {
            
            return this.affine_scale_offset(scale, offset);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移
         * @param scale x,y 方向的 缩放比例
         * @param offsetx x方向平移量
         * @param offsety y方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine1(final Number scale, final Number offsetx, final Number offsety) {
            
            return this.affine_scale_offset(scale,scale, offsetx, offsety);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移
         * @param scalex x方向缩放比例
         * @param scaley y方向缩放比例
         * @param offset x与y 方向上的 平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine2(final Number scalex, final Number scaley, final Number offset) {
            
            return this.affine_scale_offset(scalex, scaley, offset, offset);
        }
        
        /**
         * 仿射变换<br>
         * 先缩放然后平移 : affine_scale_offset 的别名
         * @param scalex x方向缩放比例
         * @param scaley y方向缩放比例
         * @param offsetx x方向平移量
         * @param offsety y方向平移量
         * @return NVec 自身以便实现链式编程
         */
        public NVec affine(final Number scalex, final Number scaley,
            final Number offsetx, final Number offsety) {
            
            return this.affine_scale_offset(scalex, scaley, offsetx, offsety);
        }

        /**
         * 提取 第 i 个索引位置 的整形值
         * @param i 元素索引号,从0开始 不成超多或等于 size
         * @return 第 i 个索引位置 的整形值
         */
        public Integer i4(final int i) {
            
            final var d = this.get(i);
            if(d==null)return null;
            
            return d.intValue();
        }
        
        /**
         * 提取 第 i 个索引位置 的 浮点数值
         * @param i 元素索引号,从0开始 不成超多或等于 size
         * @return  第 i 个索引位置 的 浮点数值
         */
        public Double dbl(final int i) {
            
            final var d = this.get(i);
            if(d==null)return null;
            
            return d.doubleValue();
        }
        
        /**
         * 提取 第 i 个索引位置 的  长整型数值
         * @param i 元素索引号,从0开始, 不成超多或等于 size
         * @return  第 i 个索引位置 的 长整型数值
         */
        public Long lng(final int i) {
            
            final var d = this.get(i);
            if(d==null)return null;
            
            return d.longValue();
        }

        /**
         * 整形数组
         * 
         * @return int[] 整形数组
         */
        public int[] ints() { // 使用for 循环单独提高效率

            final var len = this.data.length;
            final var aa = new int[len];
            for (int i = 0; i < len; i++)
                aa[i] = data[i].intValue();
            
            return aa;
        }
        
        /**
         * 整数列表
         * 
         * @return 整数列表
         */
        public List<Integer> intL() { // 使用for 循环单独提高效率

            return this.list(e->e.intValue());
        }
        
        /**
         * 整数列表
         * 
         * @return 整数列表
         */
        public Integer[] integers() { // 使用for 循环单独提高效率

            return this.list(e->e.intValue()).toArray(Integer[]::new);
        }
        
        /**
         * 浮点数数组
         * 
         * @return 浮点数数组
         */
        public double[] dbls() {
            
            final var len = this.data.length;
            final var aa = new double[len];
            for (int i = 0; i < len; i++)
                aa[i] = data[i].intValue();
            
            return aa;
        }
        
        /**
         * 浮点数列表
         * 
         * @return Double 浮点数列表
         */
        public List<Double> dblL() { // 使用for 循环单独提高效率

            return this.list(e->e);
        }
        
        /**
         * 整数列表
         * 
         * @return 整数列表
         */
        public Double[] doubles() { // 使用for 循环单独提高效率

            return this.list(e->e).toArray(Double[]::new);
        }
        
        /**
         * 长整型数组
         * 
         * @return 长整型数组
         */
        public long[] lngs() {
            
            return Stream.of(data).mapToLong(e->e.longValue()).toArray();
        }
        
        /**
         * 长整型列表
         * 
         * @return 长整型列表
         */
        public List<Long> lngL() { // 使用for 循环单独提高效率

            return this.list(e->e.longValue());
        }
        
        /**
         * 长整形数组
         * 
         * @return 整数列表
         */
        public Long[] longs() { // 使用for 循环单独提高效率

            return this.list(e->e.longValue()).toArray(Long[]::new);
        }
        
        /**
         * 提取大尾巴向量(除了1个小脑袋,其余全都是尾巴)
         * 
         * @return 除掉第一个元素的其他元素
         */
        public NVec bigtail() {
            
            return this.tail(this.size()-1);
        }

        /**
         * 提取首部向量
         * @param n,尾部元素的数量,当 n大于数组长度时,返回全体元素
         * @return 除掉最后一个元素的其他元素
         */
        public NVec tail(int n) {
            
            return new NVec(super.tail(n).data);
        }

        /**
         * 提取大脑袋向量提取大尾巴向量(除了1个小尾巴,其余全都是大脑袋)
         * 
         * @return 除掉最后一个元素的其他元素
         */
        public NVec bighead() {
            
            return this.head(this.size()-1);
        }
       
       /**
        * 提取首部向量
        * @param n 头前的元素数量,当 n大于数组长度时,返回全体元素
        * @return 除掉最后一个元素的其他元素 
        */
       public NVec head(final int n) {
           
           return new NVec(super.head(n).data);
       }
       
       /**
        * split 的 别名
        * 对data进行按照索引位置进行拆分<br>
        * <br>
        * @param <U> 数组元素类型
        * @param positions 大于0的整数列表,表示切分的位点, 即切分索引位置<br>
        * 切分索引位置（区间结尾索引exclusive,所以需要的是大约0的整数） 序列,<br>
        * 对于超出过data.length则视为数组的最大长度,<br>
        * 剔除超过数组长度范围所分割的区间。<br>
        * - 比如： [0,1,2,3],按照 {2,5,6}进行切分,定义的区间为:<br>
        * [0,2),[2,5),[5,6),由于[2,5)区间跨越了 data的长度,<br>
        * 所以给他矫正为[2,3),[5,6) 区间给予剔除。<br>
        * 结果返回 [0,1],[2,3]。<br>
        * - 比如：[0,1,2,3],按照[ 2 ] 进行切分,定义了区间 [0,2),[2,4),<br>
        * 即 定义区间的时候，会自动 补填 0,和 数组常常作为分割点。<br>
        * 即对于一个长度为4的数组来说,切分简化序列 [2]相当于 [0,2,4]的 切分完整序列。
        * @return 分割片段
        */
       public List<NVec> cuts(final Integer ...positions){
           
           return split(data,positions).stream().map(NVec::of).collect(Collectors.toList());
       }
       
       /**
        * 对data进行按照索引位置进行拆分<br>
        * <br>
        * @param <U> 数组元素类型
        * @param positions 大于0的整数列表,表示切分的位点, 即切分索引位置<br>
        * 切分索引位置（区间结尾索引exclusive,所以需要的是大约0的整数） 序列,<br>
        * 对于超出过data.length则视为数组的最大长度,<br>
        * 剔除超过数组长度范围所分割的区间。<br>
        * - 比如： [0,1,2,3],按照 {2,5,6}进行切分,定义的区间为:<br>
        * [0,2),[2,5),[5,6),由于[2,5)区间跨越了 data的长度,<br>
        * 所以给他矫正为[2,3),[5,6) 区间给予剔除。<br>
        * 结果返回 [0,1],[2,3]。<br>
        * - 比如：[0,1,2,3],按照[ 2 ] 进行切分,定义了区间 [0,2),[2,4),<br>
        * 即 定义区间的时候，会自动 补填 0,和 数组常常作为分割点。<br>
        * 即对于一个长度为4的数组来说,切分简化序列 [2]相当于 [0,2,4]的 切分完整序列。
        * @return 向量被cuts后所得到一个以片段选择器
        */
       public Function<Integer,NVec> cuts_picker(final Integer ...positions){
           
           final var ll = this.cuts(positions);
           
           return n->{
               final var size = ll.size();
               if(size<0||n>=size)return null;
               return ll.get(n);
           };
       }
       
       /**
         * 文本格式化
         */
        public String toString() {
            
            return Arrays.toString(data);
        }
        
        /**
            * 整形的除法:a/b <br>
            * intdiv 可以用于求出一个 按照行顺序的 索引a,在按照行的长度为b进行展开后的所产生的矩阵 <br>
            * 的二维坐标.比如 对于 对于索引4,当按照b=3的周期(行长度)进行提升高纬度后他的他的二维索引就编程 <br>
            * [1,1],即 intdiv(4,3)的结果。<br>
            * 一种展开的索引结构示例<br>
            * [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] <br>
            * [0.0, 0.0]|0.0   [0.0, 1.0]|1.0  [0.0, 2.0]|2.0   <br>
            * [1.0, 0.0]|3.0   [1.0, 1.0]|4.0  [1.0, 2.0]|5.0   <br>
            * [2.0, 0.0]|6.0   [2.0, 1.0]|7.0  [2.0, 2.0]|8.0   <br>
            * 
            * @param a 除数 
            * @param b 被除数
            * @return 第0位 商,第一位余数
            */
           public static NVec intdiv(final Number a, final Number b) {
               return NVec.of(new int[]{a.intValue()/b.intValue(),a.intValue()%b.intValue()});
           }

        /**
         * 构造一个NVec对象
         * @param rng 区间范围
         * @return NVec 实例以便实现链式编程
         */
        public static NVec of(final Range rng) {
            
            return new NVec(rng);
        }

        /**
         * 构造一个NVec对象
         * @param nvec 拷贝一个 nvec
         * @return NVec 实例以便实现链式编程
         */
        public static NVec of(final NVec nvec) {
            
            return new NVec(nvec.toArray());
        }

        /**
         * 构造一个NVec对象
         * @param data 向量的数据元素序列
         * @return NVec 实例以便实现链式编程
         */
        public static NVec of(final Number ... data) {
            
            return new NVec(data);
        }
        
        /**
         * 构造一个NVec对象
         * @param ll 列表类型的数据
         * @return NVec 实例以便实现链式编程
         */
        public static NVec of(final List<? super Number> ll) {
            final var aa = ll.toArray(Number[]::new);
            return new NVec(aa);
        }

        /**
         * 构造一个NVec对象
         * @param data 向量的数据元素序列
         * @return NVec 实例以便实现链式编程
         */
        public static NVec of(final int [] data) {
            
            return new NVec(data);
        }
        
        /**
         * 生成一个 双精度(Double[][] 类型)二维矩阵 (主顺序为行序的 矩阵  即 行序矩阵)<br>
         * 
         * 数组 的 第一索引顺序 与  stream 的元素序列顺序相同 <br>
         * 数组 的 第而索引顺序 与  NVec 的元素序列顺序相同 <br> 
         * 即 返回的矩阵的 维度为 :  n x size <br>
         * n 是 stream 长度,size 是  NVec 的长度 <br> 
         * 
         * @param stream NVec的流
         * @return 双精度二维矩阵 。矩阵的 维度 n x size
         */
        public static Double[][] toArray2( final Stream<NVec> stream){
            
            return stream.map(e->e.data).toArray(Double[][]::new);
        }

        /**
         * 生成一个 双精度二维矩阵 (主顺序为行序的 矩阵 即 行序矩阵 )<br>
         * 
         * 数组 的 第一索引顺序 与  stream 的元素序列顺序相同 <br>
         * 数组 的 第而索引顺序 与  NVec 的元素序列顺序相同 <br> 
         * 即 返回的矩阵的 维度为 :  n x size <br>
         * n 是 stream 长度,size 是  NVec 的长度 <br> 
         * 
         * @param stream NVec的流
         * @return 双精度二维矩阵 。矩阵的 维度 n x size
         */
        public static double[][] toArray( final Stream<NVec> stream){
            
            return stream.map(NVec::dbls).toArray(double[][]::new);
        }
        
    }// NVec
    
    /**
     * 连续性线条的填充算法算法：<br>
     * 根据前一个节点的y值构造连续线条 <br>
     * @return 连续性线条绘制方法
     */
    public static Function<int[],Stream<int[]>> continuous_line(){
        
        return continuous_line(false);
    }
    
    /**
     * 连续性线条的填充算法算法：<br>
     * 根据前一个节点的y值构造连续线条 <br>
     * @param prev_exclusive prev在是否在连续性补充中给与排除,true 不从prev开始,false从prev开始<br>
     * 实验证明从prev[1]包含绘制 要比 不包含绘制要好。在绘制正余弦曲线的时候 prev[1] 不包含<br>
     * 会造成断连现象。建议设置成 false，表示包含prev,从前一点高度位置上多补一个像素。以增加连续性
     * @return 连续性线条绘制方法
     */
    public static Function<int[],Stream<int[]>> continuous_line(boolean prev_exclusive){
        
        final var atom_prev = new AtomicReference<int[]>();// 前一个点状态缓存
        
        return e -> { // 填充点e 表示 像素点的颜色向量[x,y,r,g,b], 0#x,1#y,表示像素点e的坐标,后续为rgb颜色值
            final var prev = atom_prev.getAndSet(e); // 前一个节点
            
            return prev == null //
            ? Stream.of(e)  // 第一个数据点
              // 实验证明从prev[1]包含绘制 要比 不包含绘制要好,对于正余弦曲线的经验 prev[1] 不包含,会造成断连现象。
            : (prev_exclusive // prev是否包含
               ? Range.of12(prev[1],e[1]) // prev[1] 不包含
               : Range.of2(prev[1],e[1]) //  prev[1] 包含
              ).mapInt(i->NVec.of(e).idval_set(1, i).ints()); // 从第二个点开始做连续性填充
        }; // e 
    }

    /**
     * 矩阵化一个向量 <br>
     * 一个index2value列表 等价于一个矩阵。
     * 
     * @param <T> 向量的元素类型
     * @param <U> 矩阵的元素类型
     * @param vectors 数据向量
     * @param indexer 行号 列号 t->{行索引,列索引}
     * @param valueer 值提取 t->u 
     * @return U[][] 结果矩阵
     */
    @SuppressWarnings("unchecked")
    public static <T,U> U[][] matrix (
        final List<T> vectors,
        final Function<T,int[]> indexer,
        final Function<T,U> valueer ){
        
        final int aa[]= {0,0};// 临时数据空间，用来统计第一维度，第二维度的最大数据。以方便生成结果矩阵的宽度和高度。
        final var idxvalues = IndexValuePair.analyze ( vectors, indexer, valueer, IndexValuePair::new,
            ivp->{// 中间结果处理
                final var index = ivp.index; // 提取索引值
                if(aa[0]<index[0]) aa[0] = index[0];
                if(aa[1]<index[1]) aa[1] = index[1];
        }).collect(Collectors.toList()); // 注意一定要启动Collectors做列表化操作，以完成实际的数据搜集工作，否则aa不会做更新。
        final Class<U> clazz = IndexValuePair.getValClazz(idxvalues).orElse((Class<U>)Object.class);
        final int width = aa[0]+1;// 矩阵宽度
        final int height = aa[1]+1; // 高度
        final var uu = (U[][])Array.newInstance(clazz, width,height); // 结果的二维矩阵数组
        
        // 索引值数据 ivps 填充到目标结构数组之中
        for( final IndexValuePair<U> idxval: idxvalues ) idxval.assignTo(uu);
        
        return uu;// 返回二维矩阵数组。
    }

    /**
     * 直线绘制算法<br>
     * bresenham_line 的算法特点就是 只有 整数运算，没有 浮点运算，这就是它的高妙的地方。<br>
     * @param x0 开始点  x
     * @param y0 开始点  y
     * @param x1 终止点  x
     * @param y1 终止点  y
     * @param setPixel 点绘制函数
     */
    public static void bresenham_line(
        final int x0, int y0, 
        final int x1, final int y1, 
        final BiConsumer<Integer, Integer> setPixel) {
        
        int dx = x1 - x0; // x 方向的延展跨度
        int dy = y1 - y0; // y 方向的延展跨度
        int ux = dx > 0 ? 1 : -1;// x的增量单位，取1或-1
        int uy = dy > 0 ? 1 : -1;// y的增量单位，取1或-1
        int x = x0; // 当前节点的横坐标
        int y = y0; // 当前节点的纵坐标
        int eps = 0; // eps为累加误差
        
        dx = Math.abs(dx);
        dy = Math.abs(dy);
        
        if (dx > dy) { // 按  x 轴向 进行展开,简单的说就是 就是提取延展跨度最大的方向做为主方向。
            for (x = x0; x != x1; x += ux) {
                setPixel.accept(x, y);
                eps += dy;
                if ((eps << 1) >= dx) {
                    y += uy;
                    eps -= dx;
                }// if
            }// for
        } else { // 按  y 轴向 进行展开
            for (y = y0; y != y1; y += uy) {
                setPixel.accept(x, y);
                eps += dx;
                if ((eps << 1) >= dy) {
                    x += ux;
                    eps -= dy;
                }// if
            }// for
        } // if
    }
    
    /**
     * 生成一个5*5的[R,I] 旋转矩阵(左乘结构)    <br>
     * R 是一个2x2维的旋转子矩阵:<br>
     * cos(theta)    -sin(theta)        <br>
     * sin(theta)    cos(theta)        <br>
     * I 是一个3x3维的单位矩阵。             <br>
     * @param theta 旋转角度(正方向为逆时针方向)
     * @return 旋转矩阵[R,I]
     */
    public static DataMatrix<Double> rotateMx(final double theta) {
        
        return rotateMx(theta,e->e);
    }
    
    /**
     * 生成一个5*5的[R,I] 旋转矩阵(左乘结构)    <br>
     * R 是一个2x2维的旋转子矩阵:<br>
     * cos(theta)    -sin(theta)        <br>
     * sin(theta)    cos(theta)        <br>
     * I 是一个3x3维的单位矩阵。             <br>
     * @param <T> 返回值的类型即mapper的结果类型
     * @param theta 旋转角度(正方向为逆时针方向)
     * @param mapper 矩阵变换器 : mx 5*5矩阵 -> t
     * @return 旋转矩阵[R,I]
     */
    public static <T> T rotateMx(final double theta, final Function<DataMatrix<Double>,T> mapper) {
        
        final var mx = NVec.of( // 旋转矩阵
            //列向量的变换分块矩阵:坐标旋转
            cos(theta), -sin(theta),     0d,0d,0d,
            sin(theta), cos(theta),      0d,0d,0d,
            // 列向量的保留分块矩阵:颜色数据矩阵
            0d,         0d,              1d,0d,0d,
            0d,         0d,              0d,1d,0d,
            0d,         0d,              0d,0d,1d
        ).reshape2mx(5, 5);// 随机生成一个矩阵
        
        return mapper.apply(mx);
    }
    
    /**
     * 生成一个 xyZero列向量 矩阵。<br>
     * 向量内容为:[[x],[y],[0d],[0d],[0d]]
     * @param x 第一元素
     * @param y 第二元素
     * @return xyZero列向量,[[x],[y],[0d],[0d],[0d]]
     */
    public static DataMatrix<Double> xyZero(final Number x,Number y ) {
        
        return xyZero(x,y,e->e);
    }
    
    /**
     * 生成一个 xyZero列向量 矩阵。<br>
     * 向量内容为:[[x],[y],[0d],[0d],[0d]]
     * @param <T> 返回值的类型即mapper的结果类型
     * @param x 第一元素
     * @param y 第二元素
     * @param mapper 矩阵变换器：mx 5*1 列向量矩阵 -> t
     * @return xyZero列向量,[[x],[y],[0d],[0d],[0d]]
     */
    public static <T> T xyZero(final Number x, final Number y, final Function<DataMatrix<Double>,T> mapper ) {
        
        final var mx = NVec.of(x.doubleValue(),y.doubleValue(),0d,0d,0d).reshape2mx(5, 1);
        
        return mapper.apply(mx);
    }
    
    /**
     * 生成一个2pi周期间隔的采样点 <br>
     * 生成逻辑为 :Range.of2(-PI, PI,2*PI/n.intValue()) <br>
     * 
     * @param n : 采样点数量-1
     * @return Range 区间范围 采样点序列 控制结构。
     */
    public static Range range2pi(final Number n) {
        
        return Range.of2(-PI, PI,2*PI/n.intValue()); // 一个周期的采样点区间
    }
    
    /**
     * 生成一个 旋转变换函数
     * @param theta 旋转角度(正方向为逆时针方向)
     * @return 旋转变换函数
     */
    public static Function<DataMatrix<Double>,DataMatrix<Double>> rotate(final double theta) {
        
        return mx->rotateMx(theta).mmult(mx);
    }
    
    /**
     * 绘制区间:<br>
     * 主区间范围 Range[自变量定义域] <br>
     * 自变量(x或者y)在延展方向上的 取值范围。即 定义域，这是一个半闭半开空间,[start,end)
     */
    private Range range; 
    
    /**
     *  绘图画布的默认画笔色Color
     */
    private int[] color = RED; 
    
    /**
     * 是否 x,y被翻转<br>
     * 
     * true:第一索引y,第二索引x 即 颜色点向量 [y,x,r,g,b] <br>
     * false:第一索引x,第二索引y 即 颜色点向量 [x,y,r,g,b] <br>
     */
    private boolean flipFlag = false;
    
    /**
     * 回退 stack <br>
     * 保存状态过程信息 如 默认绘图色 Color,主区间范围 Range[自变量定义域] 等 的设置 已便于处理  必要的 回退请求 的数据结构
     */
    private final MultipleStack globalStack = new MultipleStack(); 
    
    public static final int[] RED = new int[] {255,0,0}; // 红色
    public static final int[] GREEN = new int[] {0,255,0}; // 绿色
    public static final int[] YELLOW = new int[] {255,255,0}; // 黄色
    public static final int[] BLUE = new int[] {0,0,255}; // 蓝色
    public static final int[] MAGENTA = new int[] {255,0,255}; // 洋红色
    public static final int[] CYAN = new int[] {0,255,255}; // 青色
    public static final int[] BLACK = new int[] {0,0,0}; // 褐色
    public static final int[] WHITE = new int[] {255,255,255}; // 白色
}